"""
Reward functions for Notion SPA tasks - V2 Architecture.

This version includes combined frontend and backend validation functions.
Each task exports a single validation function that checks both backend and frontend state.
"""

import logging
import re
from typing import Any, Callable, Dict, List, Optional, Tuple, Union
from .backend import Backend

# TaskScore type definitions for accumulated error/success tracking
from typing import Literal, TypedDict as TaskTypedDict

class ScoreMetadata(TaskTypedDict):
    success_accumulator: list[str]
    error_accumulator: list[str]

class TaskScore(TaskTypedDict):
    score: Literal[1.0, 0.0]
    metadata: ScoreMetadata

logger = logging.getLogger(__name__)
LIMIT = 500

# Helper Functions
# ==============================================================================

def _find_pages_by_title(backend: Backend, title_pattern: str) -> List[Dict[str, Any]]:
    """Find pages matching title pattern (case-insensitive regex matching)."""
    # Escape special regex characters but allow the pattern to match anywhere in the title
    escaped_pattern = re.escape(title_pattern)
    result = backend.query({
        "collection": "pages",
        "filter": {"title": {"$regex": escaped_pattern, "$options": "i"}}
    })
    if isinstance(result, list):
        return result
    return []

def _find_page_by_title(backend: Backend, title_pattern: str) -> Optional[Dict[str, Any]]:
    """Find a single page by title pattern (case-insensitive regex matching)."""
    pages = _find_pages_by_title(backend, title_pattern)
    return pages[0] if pages else None

def _find_page_by_id(backend: Backend, page_id: str) -> Dict[str, Any] | None:
    """Find a page by its _id, filtering at query level."""
    result = backend.query({"collection": "pages", "filter": {"_id": page_id}})
    if isinstance(result, list) and result:
        return result[0]
    return None

def _filter_pages_by_title(pages: List[Dict[str, Any]], title_pattern: str) -> List[Dict[str, Any]]:
    """Filter a list of pages by title pattern (case-insensitive regex matching)."""
    escaped_pattern = re.escape(title_pattern)
    pattern = re.compile(escaped_pattern, re.IGNORECASE)
    return [p for p in pages if pattern.search(p.get("title", ""))]

def _filter_page_by_title(pages: List[Dict[str, Any]], title_pattern: str) -> Optional[Dict[str, Any]]:
    """Find a single page from a list by title pattern (case-insensitive regex matching)."""
    filtered = _filter_pages_by_title(pages, title_pattern)
    return filtered[0] if filtered else None

def _get_child_pages(backend: Backend, parent_id: str) -> List[Dict[str, Any]]:
    """Get all pages with a specific parentId."""
    result = backend.query({"collection": "pages", "filter": {"parentId": parent_id}})
    if isinstance(result, list):
        return result
    return []

def _get_workspace_pages(backend: Backend, workspace_id: str) -> List[Dict[str, Any]]:
    """Get all pages in a workspace at query level."""
    result = backend.query({"collection": "pages", "filter": {"workspaceId": workspace_id}})
    if isinstance(result, list):
        return result
    return []

def _get_blocks_for_page(backend: Backend, page_id: str) -> List[Dict[str, Any]]:
    """Get all blocks for a page."""
    result = backend.query({"collection": "blocks", "filter": {"pageId": page_id}})
    if isinstance(result, list):
        return result
    return []

def _get_blocks_by_type(backend: Backend, page_id: str, block_types: List[str]) -> List[Dict[str, Any]]:
    """Get blocks for a page filtered by type(s) at query level.
    
    Args:
        backend: The backend to query
        page_id: The page ID to get blocks for
        block_types: List of block types to filter by (uses $in operator)
    
    Returns:
        List of blocks matching the page_id and any of the block_types
    """
    result = backend.query({
        "collection": "blocks",
        "filter": {
            "pageId": page_id,
            "type": {"$in": block_types}
        }
    })
    if isinstance(result, list):
        return result
    return []

def _get_todo_blocks(backend: Backend, page_id: str) -> List[Dict[str, Any]]:
    """Get todo/checkbox blocks for a page at query level."""
    return _get_blocks_by_type(backend, page_id, ["todo", "to_do", "checkbox"])

def _get_heading_blocks(backend: Backend, page_id: str, level: Optional[int] = None) -> List[Dict[str, Any]]:
    """Get heading blocks for a page at query level.
    
    Args:
        backend: The backend to query
        page_id: The page ID to get blocks for
        level: Optional heading level (1, 2, or 3). If None, gets all headings.
    """
    if level is not None:
        types = [f"heading{level}", f"heading_{level}"]
    else:
        types = ["heading1", "heading_1", "heading2", "heading_2", "heading3", "heading_3"]
    return _get_blocks_by_type(backend, page_id, types)

def _get_paragraph_blocks(backend: Backend, page_id: str) -> List[Dict[str, Any]]:
    """Get paragraph/text blocks for a page at query level."""
    return _get_blocks_by_type(backend, page_id, ["paragraph", "text"])

def _get_callout_blocks(backend: Backend, page_id: str) -> List[Dict[str, Any]]:
    """Get callout blocks for a page at query level."""
    return _get_blocks_by_type(backend, page_id, ["callout"])

def _get_code_blocks(backend: Backend, page_id: str) -> List[Dict[str, Any]]:
    """Get code blocks for a page at query level."""
    return _get_blocks_by_type(backend, page_id, ["code"])

def _get_bookmark_blocks(backend: Backend, page_id: str) -> List[Dict[str, Any]]:
    """Get bookmark blocks for a page at query level."""
    return _get_blocks_by_type(backend, page_id, ["bookmark"])

def _get_bulleted_list_blocks(backend: Backend, page_id: str) -> List[Dict[str, Any]]:
    """Get bulleted list blocks for a page at query level."""
    return _get_blocks_by_type(backend, page_id, ["bulletedList", "bulleted_list", "bulleted_list_item", "bulleted"])

def _get_numbered_list_blocks(backend: Backend, page_id: str) -> List[Dict[str, Any]]:
    """Get numbered list blocks for a page at query level."""
    return _get_blocks_by_type(backend, page_id, ["numberedList", "numbered_list", "numbered_list_item", "numbered"])

def _get_quote_blocks(backend: Backend, page_id: str) -> List[Dict[str, Any]]:
    """Get quote blocks for a page at query level."""
    return _get_blocks_by_type(backend, page_id, ["quote"])

def _get_divider_blocks(backend: Backend, page_id: str) -> List[Dict[str, Any]]:
    """Get divider blocks for a page at query level."""
    return _get_blocks_by_type(backend, page_id, ["divider"])

def _get_toggle_blocks(backend: Backend, page_id: str) -> List[Dict[str, Any]]:
    """Get toggle blocks for a page at query level."""
    return _get_blocks_by_type(backend, page_id, ["toggle"])

def _get_image_blocks(backend: Backend, page_id: str) -> List[Dict[str, Any]]:
    """Get image blocks for a page at query level."""
    return _get_blocks_by_type(backend, page_id, ["image"])

def _check_page_is_published(page: Dict[str, Any]) -> bool:
    """Check if page is published."""
    published_metadata = page.get("publishedMetadata")
    if isinstance(published_metadata, dict):
        return published_metadata.get("isPublished", False)
    return False

def _find_child_by_title(backend: Backend, parent_page: Dict[str, Any], child_title: str) -> Optional[Dict[str, Any]]:
    """Find a child page by title under a parent (case-insensitive regex matching)."""
    parent_id = parent_page.get("_id")
    escaped_pattern = re.escape(child_title)
    result = backend.query({
        "collection": "pages",
        "filter": {
            "parentId": parent_id,
            "title": {"$regex": escaped_pattern, "$options": "i"}
        }
    })
    if isinstance(result, list) and result:
        return result[0]
    return None

def _find_child_by_title_with_id(backend: Backend, parent_id: str, child_title: str) -> Optional[Dict[str, Any]]:
    """Find a child page by title under a parent ID (case-insensitive regex matching)."""
    escaped_pattern = re.escape(child_title)
    result = backend.query({
        "collection": "pages",
        "filter": {
            "parentId": parent_id,
            "title": {"$regex": escaped_pattern, "$options": "i"}
        }
    })
    if isinstance(result, list) and result:
        return result[0]
    return None

def _find_root_pages_by_title(backend: Backend, title_pattern: str) -> List[Dict[str, Any]]:
    """Find root-level pages (no parentId) matching title pattern."""
    escaped_pattern = re.escape(title_pattern)
    result = backend.query({
        "collection": "pages",
        "filter": {
            "parentId": None,
            "title": {"$regex": escaped_pattern, "$options": "i"}
        }
    })
    if isinstance(result, list):
        return result
    return []

def _find_root_page_by_title(backend: Backend, title: str) -> Optional[Dict[str, Any]]:
    """Find a root-level page (no parent) by exact title at query level."""
    result = backend.query({
        "collection": "pages",
        "filter": {
            "title": title,
            "parentId": None
        }
    })
    if isinstance(result, list) and result:
        return result[0]
    return None

def _get_root_pages(backend: Backend) -> List[Dict[str, Any]]:
    """Get all root-level pages (no parentId)."""
    result = backend.query({
        "collection": "pages",
        "filter": {"parentId": None}
    })
    if isinstance(result, list):
        return result
    return []

def _get_page_by_id(backend: Backend, page_id: str) -> Optional[Dict[str, Any]]:
    """Get a single page by its ID."""
    result = backend.query({
        "collection": "pages",
        "filter": {"_id": page_id}
    })
    if isinstance(result, list) and result:
        return result[0]
    return None

def _find_pages_with_all_title_patterns(backend: Backend, patterns: List[str]) -> List[Dict[str, Any]]:
    """Find pages whose title contains ALL of the given patterns (case-insensitive)."""
    if not patterns:
        return []

    # Build regex that matches all patterns (in any order)
    # Use positive lookahead for each pattern
    regex_parts = [f"(?=.*{re.escape(p)})" for p in patterns]
    combined_regex = "".join(regex_parts) + ".*"

    result = backend.query({
        "collection": "pages",
        "filter": {
            "title": {"$regex": combined_regex, "$options": "i"}
        }
    })
    if isinstance(result, list):
        return result
    return []

def _find_page_with_all_title_patterns(backend: Backend, patterns: List[str]) -> Optional[Dict[str, Any]]:
    """Find a single page whose title contains ALL of the given patterns (case-insensitive)."""
    pages = _find_pages_with_all_title_patterns(backend, patterns)
    return pages[0] if pages else None

def _find_page_by_title_and_parent(backend: Backend, title: str, parent_id: str) -> Optional[Dict[str, Any]]:
    """Find a page by exact title and parent ID at query level."""
    result = backend.query({
        "collection": "pages",
        "filter": {
            "title": title,
            "parentId": parent_id
        }
    })
    if isinstance(result, list) and result:
        return result[0]
    return None

def _find_page_by_title_pattern_and_parent(backend: Backend, title_pattern: str, parent_id: str) -> Optional[Dict[str, Any]]:
    """Find a page by title pattern (case-insensitive) and parent ID at query level."""
    escaped_pattern = re.escape(title_pattern)
    result = backend.query({
        "collection": "pages",
        "filter": {
            "title": {"$regex": escaped_pattern, "$options": "i"},
            "parentId": parent_id
        }
    })
    if isinstance(result, list) and result:
        return result[0]
    return None

def _find_page_by_title_and_workspace(backend: Backend, title_pattern: str, workspace_id: str) -> Optional[Dict[str, Any]]:
    """Find a page by title pattern (case-insensitive) and workspace ID at query level."""
    escaped_pattern = re.escape(title_pattern)
    result = backend.query({
        "collection": "pages",
        "filter": {
            "title": {"$regex": escaped_pattern, "$options": "i"},
            "workspaceId": workspace_id
        }
    })
    if isinstance(result, list) and result:
        return result[0]
    return None

def _check_page_is_child_of(parent_page: Dict[str, Any], child_page: Dict[str, Any]) -> bool:
    """Check if child_page is a child of parent_page (by ID relationship)."""
    return child_page.get("parentId") == parent_page.get("_id")

def _check_page_has_collaborator(page: Dict[str, Any], email: str, access_level: Optional[str] = None) -> bool:
    """Check if page has a collaborator with given email and optionally access level (case-insensitive)."""
    sharing_metadata = page.get("sharingMetadata")
    if not isinstance(sharing_metadata, dict):
        return False

    collaborators = sharing_metadata.get("collaborators", [])
    if not isinstance(collaborators, list):
        return False

    email_lower = email.lower()
    for collab in collaborators:
        if isinstance(collab, dict):
            collab_email = collab.get("email", "")
            if collab_email and email_lower in collab_email.lower():
                if access_level is None:
                    return True
                if collab.get("accessLevel") == access_level:
                    return True
    return False

def _check_page_is_public(page: Dict[str, Any]) -> bool:
    """Check if page is publicly shared or published to web."""
    # Check publishedMetadata.isPublished (from "Publish to web" button)
    published_metadata = page.get("publishedMetadata")
    if isinstance(published_metadata, dict):
        if published_metadata.get("isPublished", False):
            return True
    # Also check sharingMetadata.isPublic (legacy/alternative public sharing)
    sharing_metadata = page.get("sharingMetadata")
    if isinstance(sharing_metadata, dict):
        if sharing_metadata.get("isPublic", False):
            return True
    return False

def _check_page_is_archived(page: Dict[str, Any]) -> bool:
    """Check if page is archived."""
    return page.get("isArchived", False)

def _check_page_is_favorite(page: Dict[str, Any]) -> bool:
    """Check if page is favorited."""
    return page.get("isFavorite", False)

def _check_page_icon(page: Dict[str, Any], expected_icon: str) -> bool:
    """Check if page has the expected icon."""
    return page.get("icon") == expected_icon

def _count_descendant_pages(backend: Backend, parent_id: str) -> int:
    """Count all descendant pages (children, grandchildren, etc.) of a parent."""
    count = 0
    children = _get_child_pages(backend, parent_id)
    for child in children:
        count += 1
        count += _count_descendant_pages(backend, child.get("_id", ""))
    return count

def _has_block_type(blocks: List[Dict[str, Any]], block_type: str) -> bool:
    """Check if any block matches the specified type."""
    return any(b.get("type") == block_type for b in blocks)

def _has_block_with_content(blocks: List[Dict], content_pattern: str, block_type: str = None) -> bool:
    """Check if blocks contain content pattern (case-insensitive)."""
    pattern_lower = content_pattern.lower()
    for b in blocks:
        if block_type and b.get("type") != block_type:
            continue
        if pattern_lower in b.get("content", "").lower():
            return True
    return False

def _find_block_index(blocks: List[Dict], content_pattern: str, block_type: str = None) -> Optional[int]:
    """Find index of block with content pattern."""
    pattern_lower = content_pattern.lower()
    for idx, b in enumerate(blocks):
        if block_type and b.get("type") != block_type:
            continue
        if pattern_lower in b.get("content", "").lower():
            return idx
    return None

def _count_blocks_by_type(blocks: List[Dict], block_type: str) -> int:
    """Count blocks of a specific type."""
    return sum(1 for b in blocks if b.get("type") == block_type)

def _count_todos(blocks: List[Dict]) -> Tuple[int, int, int]:
    """Count total, checked, unchecked todos."""
    todos = [b for b in blocks if b.get("type") == "todo"]
    total = len(todos)
    checked = sum(1 for t in todos if t.get("properties", {}).get("checked", False))
    return total, checked, total - checked

def _has_callout_with_bg(blocks: List[Dict], bg_pattern: str) -> bool:
    """Check if there's a callout with specific background color."""
    bg_lower = bg_pattern.lower()
    for b in blocks:
        if b.get("type") == "callout":
            props = b.get("properties", {})
            bg = props.get("backgroundColor", "")
            if bg_lower in bg.lower():
                return True
    return False

def _has_code_block_with_lang(blocks: List[Dict], language: str) -> bool:
    """Check if there's a code block with specific language."""
    lang_lower = language.lower()
    for b in blocks:
        if b.get("type") == "code":
            props = b.get("properties", {})
            lang = props.get("language", "")
            if lang_lower in lang.lower():
                return True
    return False

def _check_text_is_bold(content: str, props: Dict[str, Any], text_pattern: Optional[str] = None) -> bool:
    """Check if text is bold via markdown (**text**) or bold property.
    
    Args:
        content: The text content to check
        props: Block properties dict (may contain 'bold' key)
        text_pattern: Optional pattern to match within bold markers. If None, checks for any bold.
    
    Returns:
        True if text is bold (via markdown or property), False otherwise
    """
    # Check block-level bold property
    if props.get("bold", False):
        return True
    
    # Check markdown-style bold (**text**)
    if text_pattern:
        # Escape the text pattern for regex
        escaped_pattern = re.escape(text_pattern)
        # Replace escaped spaces with \s+ to allow flexible whitespace matching
        escaped_pattern = escaped_pattern.replace(r'\ ', r'\s+')
        
        # Check for exact match: **text_pattern** (with optional whitespace around pattern)
        # This ensures the text_pattern is directly within bold markers, not just somewhere in a larger bold section
        pattern = r'\*\*\s*' + escaped_pattern + r'\s*\*\*'
        if re.search(pattern, content, re.IGNORECASE):
            return True
    else:
        # Check for any bold markers
        if re.search(r'\*\*[^*]+\*\*', content):
            return True
    
    return False

def _check_text_is_italic(content: str, props: Dict[str, Any], text_pattern: Optional[str] = None) -> bool:
    """Check if text is italic via markdown (*text* or _text_) or italic property.
    
    Args:
        content: The text content to check
        props: Block properties dict (may contain 'italic' key)
        text_pattern: Optional pattern to match within italic markers. If None, checks for any italic.
    
    Returns:
        True if text is italic (via markdown or property), False otherwise
    """
    # Check block-level italic property
    if props.get("italic", False):
        return True
    
    # Check markdown-style italic (*text* or _text_)
    if text_pattern:
        # Escape the text pattern for regex
        escaped_pattern = re.escape(text_pattern)
        # Replace escaped spaces with \s+ to allow flexible whitespace matching
        escaped_pattern = escaped_pattern.replace(r'\ ', r'\s+')
        
        # Check *text* style - ensure text_pattern is directly within asterisk markers
        # This ensures the text_pattern is directly within italic markers, not just somewhere in a larger italic section
        pattern_asterisk = r'\*\s*' + escaped_pattern + r'\s*\*'
        if re.search(pattern_asterisk, content, re.IGNORECASE):
            return True
        # Check _text_ style - ensure text_pattern is directly within underscore markers
        pattern_underscore = r'_\s*' + escaped_pattern + r'\s*_'
        if re.search(pattern_underscore, content, re.IGNORECASE):
            return True
    else:
        # Check for any italic markers
        if re.search(r'\*[^*]+\*', content) or re.search(r'_[^_]+_', content):
            return True
    
    return False

def _check_email_matches(collab_email: str, target_email: str) -> bool:
    """Check if collaborator email matches target (case-insensitive)."""
    return collab_email.lower() == target_email.lower()

def _check_page_has_links(backend: Backend, page_id: str) -> bool:
    """Check if a page has links (bookmark blocks or content with URLs)."""
    blocks = _get_blocks_for_page(backend, page_id)
    for block in blocks:
        block_type = block.get("type")
        properties = block.get("properties", {})
        if block_type == "bookmark" or properties.get("url"):
            return True
        # Check if content contains links (basic check)
        content = block.get("content", "")
        if "http" in content.lower() or "link" in content.lower():
            return True
    return False

def _count_heading_blocks(blocks: List[Dict[str, Any]]) -> int:
    """Count the number of heading blocks (heading1, heading2, heading3)."""
    heading_types = {"heading1", "heading2", "heading3"}
    return sum(1 for b in blocks if b.get("type") in heading_types)

def _is_calendar_icon(icon: str | None) -> bool:
    """Check if the icon is a calendar emoji."""
    if not icon:
        return False
    calendar_icons = {"📅", "🗓️", "🗓", "📆"}
    return icon in calendar_icons

def _is_graduation_cap_icon(icon: str | None) -> bool:
    """Check if the icon is a graduation cap emoji."""
    if not icon:
        return False
    graduation_icons = {"🎓", "👩‍🎓", "👨‍🎓"}
    return icon in graduation_icons

def _count_blocks_of_type(blocks: List[Dict[str, Any]], block_type: str) -> int:
    """Count blocks of a specified type."""
    return sum(1 for b in blocks if b.get("type") == block_type)

def _is_document_icon(icon: str | None) -> bool:
    """Check if the icon is a document emoji."""
    if not icon:
        return False
    document_icons = {"📄", "📃", "📋", "📝", "📑", "🗎", "🗏"}
    return icon in document_icons

def _has_heading_block(blocks: List[Dict[str, Any]]) -> bool:
    """Check if any block is a heading (heading1, heading2, or heading3)."""
    heading_types = {"heading1", "heading2", "heading3"}
    return any(b.get("type") in heading_types for b in blocks)

def _is_lightbulb_icon(icon: str | None) -> bool:
    """Check if the icon is a lightbulb emoji."""
    if not icon:
        return False
    return icon in {"💡", "🔦", "✨"}

def _is_brain_icon(icon: str | None) -> bool:
    """Check if the icon is a brain emoji."""
    if not icon:
        return False
    return icon in {"🧠", "🧩"}

def _is_people_icon(icon: str | None) -> bool:
    """Check if the icon is a people/team emoji."""
    if not icon:
        return False
    people_icons = {"👥", "👨‍👩‍👧‍👦", "👪", "🧑‍🤝‍🧑", "👫", "👬", "👭", "🤝", "👨‍👩‍👧", "👨‍👩‍👦"}
    return icon in people_icons

def _is_gear_icon(icon: str | None) -> bool:
    """Check if the icon is a gear/tool emoji."""
    if not icon:
        return False
    gear_icons = {"⚙️", "🔧", "🛠️", "⚒️", "🔩", "⚙"}
    return icon in gear_icons

def _is_heart_icon(icon: str | None) -> bool:
    """Check if the icon is a heart emoji."""
    if not icon:
        return False
    heart_icons = {"❤️", "💖", "💗", "💕", "♥️", "💜", "💙", "💚", "🧡", "💛", "🤍", "🖤", "💝", "💞", "💓", "💘"}
    return icon in heart_icons

def _is_target_icon(icon: str | None) -> bool:
    """Check if the icon is a target emoji."""
    if not icon:
        return False
    return icon in {"🎯"}

def _is_handshake_icon(icon: str | None) -> bool:
    """Check if the icon is a handshake emoji."""
    if not icon:
        return False
    return icon in {"🤝"}

def _is_trophy_icon(icon: str | None) -> bool:
    """Check if the icon is a trophy emoji."""
    if not icon:
        return False
    trophy_icons = {"🏆", "🥇", "🏅", "🎖️"}
    return icon in trophy_icons

def _is_folder_icon(icon: str | None) -> bool:
    """Check if the icon is a folder emoji."""
    if not icon:
        return False
    folder_icons = {"📁", "📂", "🗂️", "🗂"}
    return icon in folder_icons

def _is_rocket_icon(icon: str | None) -> bool:
    """Check if the icon is a rocket emoji."""
    if not icon:
        return False
    return icon in {"🚀"}

def _get_all_descendant_pages_from_backend(backend: Backend, parent_id: str) -> List[Dict[str, Any]]:
    """Recursively get all descendant pages of a given parent using query-level filtering."""
    descendants = []
    children = _get_child_pages(backend, parent_id)

    for child in children:
        descendants.append(child)
        child_id = child.get("_id")
        if child_id:
            # Recursively get children of this child
            descendants.extend(_get_all_descendant_pages_from_backend(backend, child_id))

    return descendants

def _extract_number_from_bullet(text: str) -> int | None:
    """Extract number from bullet text like '• Block count: 5' -> 5."""
    import re
    match = re.search(r':\s*(\d+)', text)
    if match:
        return int(match.group(1))
    return None

def _extract_type_from_bullet(text: str) -> str | None:
    """Extract type from bullet text like '• Most common block type: paragraph' -> 'paragraph'."""
    import re
    match = re.search(r':\s*(\w+)', text)
    if match:
        return match.group(1)
    return None

def _extract_date_from_bullet(text: str) -> str | None:
    """Extract date from bullet text like '• Last updated: 2024-01-15' -> '2024-01-15'."""
    import re
    match = re.search(r':\s*(\d{4}-\d{2}-\d{2})', text)
    if match:
        return match.group(1)
    return None

def _format_date_from_iso(iso_string: str) -> str | None:
    """Convert ISO timestamp to YYYY-MM-DD format."""
    if not iso_string:
        return None
    try:
        from datetime import datetime
        dt = datetime.fromisoformat(iso_string.replace('Z', '+00:00'))
        return dt.strftime('%Y-%m-%d')
    except Exception:
        return None

def _get_most_common_block_type(blocks: List[Dict[str, Any]]) -> str | None:
    """Return the most frequent block type. In case of tie, returns one of the tied types."""
    if not blocks:
        return None
    
    from collections import Counter
    type_counts = Counter(b.get("type") for b in blocks if b.get("type"))
    
    if not type_counts:
        return None
    
    # Get the most common type(s)
    most_common = type_counts.most_common(1)
    return most_common[0][0] if most_common else None

def _get_code_blocks_by_page_from_backend(backend: Backend) -> Dict[str, List[Dict[str, Any]]]:
    """Get all code blocks from backend and group by pageId using query-level filtering."""
    result = backend.query({"collection": "blocks", "filter": {"type": "code"}})
    code_blocks = result if isinstance(result, list) else []
    from collections import defaultdict
    by_page = defaultdict(list)
    for block in code_blocks:
        page_id = block.get("pageId")
        if page_id:
            by_page[page_id].append(block)
    return dict(by_page)

def _count_languages_on_page(code_blocks: List[Dict[str, Any]]) -> Dict[str, int]:
    """Count code blocks by language on a specific page."""
    from collections import Counter
    languages = [b.get("properties", {}).get("language", "unknown") 
                 for b in code_blocks]
    return dict(Counter(languages))

def _parse_language_count_from_numbered_list(content: str) -> tuple[str, int] | None:
    """Parse '1. JavaScript - 5 examples' -> ('javascript', 5)."""
    import re
    match = re.search(r'(\w+)\s*-\s*(\d+)\s*examples?', content, re.IGNORECASE)
    if match:
        return (match.group(1).lower(), int(match.group(2)))
    return None

def _parse_language_count_from_todo(content: str) -> tuple[str, int] | None:
    """Parse 'Review JavaScript fundamentals (5 examples available)' -> ('javascript', 5)."""
    import re
    match = re.search(r'Review\s+(\w+)\s+fundamentals\s*\((\d+)\s*examples?\s+available\)', 
                      content, re.IGNORECASE)
    if match:
        return (match.group(1).lower(), int(match.group(2)))
    return None

def _extract_icon_and_title_from_heading(content: str) -> tuple[str, str] | None:
    """Extract icon and title from '💻 Code Examples Repository'."""
    if len(content) < 2:
        return None
    # First character is likely emoji, rest is title
    icon = content[0]
    title = content[1:].strip()
    return (icon, title)

def _build_page_hierarchy(
    final_state_backend: Backend,
    root_page_id: str,
    visited: Optional[set] = None
) -> Dict[str, Any]:
    """Build a nested hierarchy structure for pages starting from root."""
    if visited is None:
        visited = set()
    
    if root_page_id in visited:
        return {}
    
    visited.add(root_page_id)
    
    root_page = _get_page_by_id(final_state_backend, root_page_id)
    if not root_page:
        return {}
    
    children = _get_child_pages(final_state_backend, root_page_id)
    hierarchy = {
        "page": root_page,
        "children": []
    }
    
    for child in children:
        child_hierarchy = _build_page_hierarchy(final_state_backend, child.get("_id"), visited)
        if child_hierarchy:
            hierarchy["children"].append(child_hierarchy)
    
    return hierarchy

def _count_pages_in_hierarchy(hierarchy: Dict[str, Any]) -> int:
    """Count total pages in a hierarchy tree."""
    count = 1  # Count the root page
    for child in hierarchy.get("children", []):
        count += _count_pages_in_hierarchy(child)
    return count

def _get_all_pages_in_hierarchy(hierarchy: Dict[str, Any]) -> List[Dict[str, Any]]:
    """Get all pages in a hierarchy tree as a flat list."""
    pages = [hierarchy["page"]]
    for child in hierarchy.get("children", []):
        pages.extend(_get_all_pages_in_hierarchy(child))
    return pages

def _get_pages_from_backend(backend: Backend, filter: Optional[Dict[str, Any]] = None) -> List[Dict[str, Any]]:
    """Get pages from backend with optional filter.
    
    Args:
        backend: Backend instance
        filter: Optional filter dict, e.g. {"title": {"$regex": "pattern", "$options": "i"}}
    """
    result = backend.query({"collection": "pages", "filter": filter or {}})
    if isinstance(result, list):
        return result
    return []

def _get_blocks_from_backend(backend: Backend, filter: Optional[Dict[str, Any]] = None) -> List[Dict[str, Any]]:
    """Get blocks from backend with optional filter.
    
    Args:
        backend: Backend instance
        filter: Optional filter dict, e.g. {"pageId": "some-id"}
    """
    result = backend.query({"collection": "blocks", "filter": filter or {}})
    if isinstance(result, list):
        return result
    return []

def _find_page_by_title_direct(backend: Backend, title_pattern: str) -> Optional[Dict[str, Any]]:
    """Find a single page by title pattern using direct backend query with $regex.
    
    Args:
        backend: Backend instance
        title_pattern: Title to search for (case-insensitive)
    
    Returns:
        First matching page or None
    """
    pages = _get_pages_from_backend(backend, {"title": {"$regex": title_pattern, "$options": "i"}})
    return pages[0] if pages else None

def _find_pages_by_title_direct(backend: Backend, title_pattern: str) -> List[Dict[str, Any]]:
    """Find pages matching title pattern using direct backend query with $regex.
    
    Args:
        backend: Backend instance
        title_pattern: Title pattern to search for (case-insensitive)
    
    Returns:
        List of matching pages
    """
    return _get_pages_from_backend(backend, {"title": {"$regex": title_pattern, "$options": "i"}})

def _get_child_pages_direct(backend: Backend, parent_id: str) -> List[Dict[str, Any]]:
    """Get all pages with a specific parentId using direct backend query.
    
    Args:
        backend: Backend instance
        parent_id: Parent page ID
    
    Returns:
        List of child pages
    """
    return _get_pages_from_backend(backend, {"parentId": parent_id})

def _get_blocks_for_page_direct(backend: Backend, page_id: str) -> List[Dict[str, Any]]:
    """Get all blocks for a page using direct backend query.
    
    Args:
        backend: Backend instance
        page_id: Page ID
    
    Returns:
        List of blocks for the page
    """
    return _get_blocks_from_backend(backend, {"pageId": page_id})

def _find_child_by_title_direct(backend: Backend, parent_id: str, child_title: str) -> Optional[Dict[str, Any]]:
    """Find a child page by title under a parent using direct backend queries.
    
    Args:
        backend: Backend instance
        parent_id: Parent page ID
        child_title: Title of child to find (case-insensitive)
    
    Returns:
        Matching child page or None
    """
    child_pages = _get_child_pages_direct(backend, parent_id)
    # Filter by title locally since we already filtered by parentId
    title_lower = child_title.lower()
    for p in child_pages:
        page_title = p.get("title", "").lower()
        if title_lower in page_title or page_title in title_lower:
            return p
    return None

def _validate_page_structure(
    backend: Backend,
    parent_page: Dict[str, Any],
    required_children: List[str],
) -> Tuple[bool, Optional[str], List[str]]:
    """Validate that a parent page has all required child pages (case-insensitive, flexible matching).

    Returns:
        (success, error_message, found_children)
    """
    found_children = []
    missing_children = []

    for required in required_children:
        found = _find_child_by_title(backend, parent_page, required)
        if found:
            found_children.append(required)
        else:
            missing_children.append(required)

    if missing_children:
        return False, f"Missing required children: {', '.join(missing_children)}", found_children

    return True, None, found_children

def _validate_frontend_viewing_page(final_state_frontend: Dict[str, Any]) -> Tuple[bool, Optional[str]]:
    """Validate that frontend is viewing a page."""
    current_page_id = final_state_frontend.get("currentPageId")
    if not current_page_id:
        return False, "Not viewing any page"
    return True, None

def _validate_pages_have_content(
    backend: Backend,
    page_ids: List[str],
    min_blocks: int = 1
) -> Tuple[bool, Optional[str]]:
    """Validate that pages have at least min_blocks content blocks."""
    for page_id in page_ids:
        blocks = _get_blocks_for_page(backend, page_id)
        if len(blocks) < min_blocks:
            # Query the page to get its title
            page_result = backend.query({"collection": "pages", "filter": {"_id": page_id}})
            page = page_result[0] if page_result else None
            page_title = page.get("title", "Unknown") if page else "Unknown"
            return False, f"Page '{page_title}' has fewer than {min_blocks} content blocks"
    return True, None

def _validate_pages_contain_text(
    backend: Backend,
    page_ids: List[str],
    required_text: Union[str, List[str]],
    case_sensitive: bool = False
) -> Tuple[bool, Optional[str]]:
    """Validate that pages contain required text in their body content.

    Args:
        backend: Backend to query
        page_ids: List of page IDs to validate
        required_text: Text or list of texts that must appear in page content.
                      If a list is provided, ALL texts must be present.
        case_sensitive: Whether text matching should be case-sensitive (default: False)

    Returns:
        Tuple of (success, error_message)
    """
    # Convert single string to list for uniform processing
    text_patterns = [required_text] if isinstance(required_text, str) else required_text

    for page_id in page_ids:
        blocks = _get_blocks_for_page(backend, page_id)
        page = _find_page_by_id(backend, page_id)
        page_title = page.get("title", "Unknown") if page else "Unknown"

        # Collect all content from blocks
        page_content = ""
        for block in blocks:
            content = block.get("content", "")
            if isinstance(content, str):
                page_content += content + " "

        # Check each required text pattern
        for pattern in text_patterns:
            search_content = page_content if case_sensitive else page_content.lower()
            search_pattern = pattern if case_sensitive else pattern.lower()

            if search_pattern not in search_content:
                return False, f"Page '{page_title}' does not contain required text: '{pattern}'"

    return True, None

def _validate_access_levels(
    page: Dict[str, Any],
    required_levels: List[str]
) -> Tuple[bool, Optional[str]]:
    """Validate that page has collaborators with required access levels."""
    sharing_metadata = page.get("sharingMetadata", {})
    collaborators = sharing_metadata.get("collaborators", [])
    
    found_levels = set()
    for collab in collaborators:
        if isinstance(collab, dict):
            level = collab.get("accessLevel")
            if level:
                found_levels.add(level)
    
    missing_levels = [level for level in required_levels if level not in found_levels]
    if missing_levels:
        return False, f"Missing access levels: {', '.join(missing_levels)}"
    
    return True, None

def _get_child_pages_from_backend(backend: Backend, parent_id: str) -> List[Dict[str, Any]]:
    """Get all child pages of a parent directly from backend using filter."""
    result = backend.query({
        "collection": "pages", 
        "filter": {"parentId": parent_id}
    })
    return result if isinstance(result, list) else []

def _get_pages(backend: Backend, title_pattern: str) -> List[Dict[str, Any]]:
    """Get pages from backend matching a title pattern (case-insensitive).
    
    Uses regex search at database level for efficiency instead of loading all pages.
    """
    # Escape special regex characters in the title pattern
    escaped_pattern = re.escape(title_pattern)
    
    # First try exact match with regex
    result = backend.query({
        "collection": "pages", 
        "filter": {"title": {"$regex": f"^{escaped_pattern}$", "$options": "i"}}
    })
    if isinstance(result, list) and result:
        return result
    
    # Then try contains match
    result = backend.query({
        "collection": "pages", 
        "filter": {"title": {"$regex": escaped_pattern, "$options": "i"}}
    })
    if isinstance(result, list) and result:
        return result
    
    # Fallback to fetching all pages (for partial reverse matches)
    all_pages = _get_pages_from_backend(backend)
    title_lower = title_pattern.lower()
    return [p for p in all_pages if p.get("title", "").lower() in title_lower]

def _get_blocks(backend: Backend, page_id: str) -> List[Dict[str, Any]]:
    """Get all blocks for a specific page from backend, sorted by order.
    
    Uses filter at database level for efficiency instead of loading all blocks.
    """
    result = backend.query({
        "collection": "blocks", 
        "filter": {"pageId": page_id}
    })
    blocks = result if isinstance(result, list) else []
    blocks.sort(key=lambda b: b.get("order", 0))
    return blocks

def _get_pages_by_filter(backend: Backend, filter: Optional[Dict[str, Any]] = None) -> List[Dict[str, Any]]:
    """Get pages from backend with optional filter.
    Args:
        backend: Backend instance
        filter: Optional filter dict, e.g. {"title": "query string"}
    """
    result = backend.query({"collection": "pages", "filter": filter or {}})
    if isinstance(result, list):
        return result
    return []

def _get_blocks_by_filter(backend: Backend, filter: Optional[Dict[str, Any]] = None) -> List[Dict[str, Any]]:
    """Get blocks from backend with optional filter.
    Args:
        backend: Backend instance
        filter: Optional filter dict, e.g. {"title": "query string"}
    """
    result = backend.query({"collection": "blocks", "filter": filter or {}})
    if isinstance(result, list):
        return result
    return []

# Reward Functions
# ==============================================================================

# Reward Functions
# ==============================================================================

# =============================================================================
# Task 7: Template Library Reorganization
# =============================================================================
def _validate_template_library_reorganization(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate template library reorganization with duplicated specialized templates."""
    errors: list[str] = []

    checks_passed = []
    
    # Check for Template Library page with bookmark icon
    try:
        template_library = _find_page_by_title(final_state_backend, "Template Library")
        if not template_library:
            errors.append("[X] Template Library page not found")
        else:
            checks_passed.append("[C] Template Library page found")
    
        # Check for bookmark icon
        icon = template_library.get("icon", "")
        if "bookmark" not in icon.lower() and "📑" not in icon and "🔖" not in icon:
            errors.append("[X] Template Library does not have a bookmark icon")
        else:
            checks_passed.append("[C] Template Library page created with bookmark icon")
    
        # Check that Template Library is marked as favorite
        if not template_library.get("isFavorite", False):
            errors.append("[X] Template Library is not marked as favorite")
        else:
            checks_passed.append("[C] Template Library marked as favorite")
    
        template_library_id = template_library.get("_id")
    
        # Find Weekly Standup Template (source for duplication)
        weekly_standup = _find_page_by_title(final_state_backend, "Weekly Standup Template")
        if not weekly_standup:
            errors.append("[X] Weekly Standup Template page not found (source for duplication)")
        else:
            checks_passed.append("[C] Weekly Standup Template found")
    
        # Check for sprint planning template (duplicate of Weekly Standup)
        sprint_planning = _find_page_by_title(final_state_backend, "sprint planning")
        if not sprint_planning:
            # Try alternative names
            sprint_planning = _find_page_by_title(final_state_backend, "Sprint Planning Template")
        if not sprint_planning:
            errors.append("[X] Sprint Planning template not found")
        else:
            checks_passed.append("[C] Sprint Planning template created")
    
        # Check for project kickoff template (duplicate of Weekly Standup)
        project_kickoff = _find_page_by_title(final_state_backend, "project kickoff")
        if not project_kickoff:
            # Try alternative names
            project_kickoff = _find_page_by_title(final_state_backend, "Project Kickoff Template")
        if not project_kickoff:
            errors.append("[X] Project Kickoff template not found")
        else:
            checks_passed.append("[C] Project Kickoff template created")
    
        # Check that both new templates have customized content with headings and todos
        for template_name, template_page in [("Sprint Planning", sprint_planning), ("Project Kickoff", project_kickoff)]:
            template_id = template_page.get("_id")
            blocks = _get_blocks_for_page(final_state_backend, template_id)
        
            # Check for heading blocks
            has_heading = any(
                b.get("type") in ["heading1", "heading2", "heading3", "heading_1", "heading_2", "heading_3"]
                for b in blocks
            )
            if not has_heading:
                errors.append(f"[X] {template_name} template does not have heading blocks")
            else:
                checks_passed.append(f"[C] {template_name} template has heading blocks")
        
            # Check for todo blocks
            has_todo = any(
                b.get("type") in ["todo", "to_do", "checkbox"]
                for b in blocks
            )
            if not has_todo:
                errors.append(f"[X] {template_name} template does not have todo/checklist blocks")
            else:
                checks_passed.append(f"[C] {template_name} template has todo/checklist blocks")
    
        checks_passed.append("[C] Both new templates have customized headings and todo checklists")
    
        # Find all pages with 'template' in the title (excluding Template Library itself)
        all_template_pages = _find_pages_by_title(final_state_backend, "template")
        template_pages = [p for p in all_template_pages if p.get("_id") != template_library_id]
    
        if len(template_pages) < 3:
            errors.append(f"[X] Expected at least 3 template pages (original + 2 new), found {len(template_pages)}")
        else:
            checks_passed.append(f"[C] Found at least 3 template pages (original + 2 new) ({len(template_pages)})")
    
        # Check that all template pages are moved under Template Library
        for template_page in template_pages:
            if template_page.get("parentId") != template_library_id:
                errors.append(f"[X] Template page '{template_page.get('title')}' is not under Template Library")
            else:
                checks_passed.append(f"[C] Template page '{template_page.get('title')}' is under Template Library")
    
        checks_passed.append(f"[C] All {len(template_pages)} template pages moved under Template Library")
    
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task 8: Template Cleanup and Centralized Library
# =============================================================================
def _validate_template_cleanup_library(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate template cleanup with centralized library and archived empty templates."""
    errors: list[str] = []

    checks_passed = []
    
    # Check for Template Library page with books icon
    try:
        template_library = _find_page_by_title(final_state_backend, "Template Library")
        if not template_library:
            errors.append("[X] Template Library page not found")
        else:
            checks_passed.append("[C] Template Library page found")
    
        # Check for books icon
        icon = template_library.get("icon", "")
        if "book" not in icon.lower() and "📚" not in icon and "📖" not in icon:
            errors.append("[X] Template Library does not have a books icon")
        else:
            checks_passed.append("[C] Template Library page created with books icon")
    
        template_library_id = template_library.get("_id")
    
        # Check that Template Library has welcome section with heading1, paragraph, and callout
        library_blocks = _get_blocks_for_page(final_state_backend, template_library_id)
    
        has_heading1 = any(
            b.get("type") in ["heading1", "heading_1"]
            for b in library_blocks
        )
        if not has_heading1:
            errors.append("[X] Template Library does not have a heading1 block")
        else:
            checks_passed.append("[C] Template Library has a heading1 block")
    
        has_paragraph = any(
            b.get("type") in ["paragraph", "text"]
            for b in library_blocks
        )
        if not has_paragraph:
            errors.append("[X] Template Library does not have a paragraph/description block")
        else:
            checks_passed.append("[C] Template Library has a paragraph/description block")
    
        has_callout = any(
            b.get("type") == "callout"
            for b in library_blocks
        )
        if not has_callout:
            errors.append("[X] Template Library does not have a callout block explaining template usage")
        else:
            checks_passed.append("[C] Template Library has a callout block explaining template usage")
    
        checks_passed.append("[C] Template Library has heading1, paragraph, and callout blocks")
    
        # Find all pages with 'Template' in the title (excluding Template Library itself)
        all_template_pages = _find_pages_by_title(final_state_backend, "template")
        template_pages = [p for p in all_template_pages if p.get("_id") != template_library_id]
    
        if len(template_pages) == 0:
            errors.append("[X] No template pages found to organize")
        else:
            checks_passed.append("[C] template pages found to organize")
    
        # Check that all non-archived template pages are moved under Template Library (filter at query level)
        active_template_pages = final_state_backend.query({
            "collection": "pages",
            "filter": {
                "title": {"$regex": "template", "$options": "i"},
                "_id": {"$ne": template_library_id},
                "$or": [{"isArchived": False}, {"isArchived": {"$exists": False}}]
            }
        })
        if not isinstance(active_template_pages, list):
            active_template_pages = []
        for template_page in active_template_pages:
            if template_page.get("parentId") != template_library_id:
                errors.append(f"[X] Template page '{template_page.get('title')}' is not under Template Library")
            else:
                checks_passed.append(f"[C] Template page '{template_page.get('title')}' is under Template Library")
    
        if len(active_template_pages) > 0:
            checks_passed.append(f"[C] All {len(active_template_pages)} active template pages moved under Template Library")
    
        # Check that empty template pages are archived
        archived_count = 0
        for template_page in template_pages:
            page_id = template_page.get("_id")
            blocks = _get_blocks_for_page(final_state_backend, page_id)
        
            # A page is considered "empty" if it has no content blocks
            is_empty = len(blocks) == 0
            is_archived = template_page.get("isArchived", False)
        
            if is_empty and is_archived:
                archived_count += 1
            elif is_empty and not is_archived:
                # Empty page not archived - this is okay if there are no empty pages
                pass
    
        # Don't fail if no empty pages exist, but check if any were archived
        if archived_count > 0:
            checks_passed.append(f"[C] {archived_count} empty template pages archived")
        else:
            checks_passed.append("[C] No empty template pages found to archive (or all archived)")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task 9: Knowledge Sharing System
# =============================================================================
def _validate_knowledge_sharing_system(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate knowledge sharing system with structured sub-pages and content."""
    errors: list[str] = []

    checks_passed = []
    
    # Check for Team Knowledge Base page with book icon
    try:
        knowledge_base = _find_page_by_title(final_state_backend, "Team Knowledge Base")
        if not knowledge_base:
            errors.append("[X] Team Knowledge Base page not found")
        else:
            checks_passed.append("[C] Team Knowledge Base page found")
    
        # Check for book icon
        icon = knowledge_base.get("icon", "")
        if "book" not in icon.lower() and "📖" not in icon and "📚" not in icon and "📕" not in icon:
            errors.append("[X] Team Knowledge Base does not have a book icon")
        else:
            checks_passed.append("[C] Team Knowledge Base page created with book icon")
    
        # Check that Team Knowledge Base is marked as favorite
        if not knowledge_base.get("isFavorite", False):
            errors.append("[X] Team Knowledge Base is not marked as favorite")
        else:
            checks_passed.append("[C] Team Knowledge Base marked as favorite")
    
        knowledge_base_id = knowledge_base.get("_id")
    
        # Check for 3 required sub-pages
        required_subpages = [
            "Best Practices",
            "Common Issues & Solutions",
            "Useful Resources"
        ]
    
        success, error, found = _validate_page_structure(final_state_backend, knowledge_base, required_subpages)
        if not success:
            errors.append(f"[X] {error}")
        else:
            checks_passed.append(f"[C] Check passed")
        checks_passed.append("[C] All 3 required sub-pages created")
    
        # Check that Best Practices page has numbered list blocks
        best_practices = _find_child_by_title(final_state_backend, knowledge_base, "Best Practices")
        if not best_practices:
            errors.append("[X] Best Practices sub-page not found")
        else:
            checks_passed.append("[C] Best Practices sub-page found")
    
        best_practices_id = best_practices.get("_id")
        best_practices_blocks = _get_blocks_for_page(final_state_backend, best_practices_id)
    
        has_numbered_list = any(
            b.get("type") in ["numberedList", "numbered_list", "numbered_list_item", "numbered"]
            for b in best_practices_blocks
        )
        if not has_numbered_list:
            errors.append("[X] Best Practices page does not have numbered list blocks for coding standards/guidelines")
        else:
            checks_passed.append("[C] Best Practices page contains numbered list blocks")
    
        # Check that main hub has callout block with contribution guidelines
        hub_blocks = _get_blocks_for_page(final_state_backend, knowledge_base_id)
    
        has_callout = any(
            b.get("type") == "callout"
            for b in hub_blocks
        )
        if not has_callout:
            errors.append("[X] Team Knowledge Base does not have a callout block with contribution guidelines")
        else:
            checks_passed.append("[C] Main hub contains callout block with contribution guidelines")
    
        # Verify all sub-pages are properly connected as children
        child_pages = _get_child_pages(final_state_backend, knowledge_base_id)
        child_titles = [p.get("title", "").lower() for p in child_pages]
    
        for required in required_subpages:
            found_match = any(
                required.lower() in title or title in required.lower()
                for title in child_titles
            )
            if not found_match:
                errors.append(f"[X] Sub-page '{required}' is not properly connected as child of Team Knowledge Base")
            else:
                checks_passed.append(f"[C] Sub-page '{required}' is properly connected as child of Team Knowledge Base")
    
        checks_passed.append("[C] All sub-pages properly connected in hierarchy")
    
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task 10: Projects Hub Organization
# =============================================================================
def _validate_projects_hub_organization(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Projects Hub organization with structured content and moved project pages."""
    errors: list[str] = []

    checks_passed = []
    
    # Check for Projects Hub page with folder icon
    try:
        projects_hub = _find_page_by_title(final_state_backend, "Projects Hub")
        if not projects_hub:
            errors.append("[X] Projects Hub page not found")
        else:
            checks_passed.append("[C] Projects Hub page found")
    
        # Check for folder icon
        icon = projects_hub.get("icon", "")
        if "folder" not in icon.lower() and "📁" not in icon and "📂" not in icon:
            errors.append("[X] Projects Hub does not have a folder icon")
        else:
            checks_passed.append("[C] Projects Hub page created with folder icon")
    
        # Check that Projects Hub is marked as favorite
        if not projects_hub.get("isFavorite", False):
            errors.append("[X] Projects Hub is not marked as favorite")
        else:
            checks_passed.append("[C] Projects Hub marked as favorite")
    
        projects_hub_id = projects_hub.get("_id")
    
        # Check that Projects Hub has proper structure with blocks
        hub_blocks = _get_blocks_for_page(final_state_backend, projects_hub_id)
    
        # Check for welcome heading (heading1 or heading2)
        has_welcome_heading = any(
            b.get("type") in ["heading1", "heading2", "heading_1", "heading_2"]
            for b in hub_blocks
        )
        if not has_welcome_heading:
            errors.append("[X] Projects Hub does not have a welcome heading block")
        else:
            checks_passed.append("[C] Projects Hub has welcome heading")
    
        # Check for explanatory paragraph
        has_paragraph = any(
            b.get("type") in ["paragraph", "text"]
            for b in hub_blocks
        )
        if not has_paragraph:
            errors.append("[X] Projects Hub does not have an explanatory paragraph block")
        else:
            checks_passed.append("[C] Projects Hub has explanatory paragraph")
    
        # Check for Active Projects and Archived Projects section headings
        # Look for headings that contain "Active" and "Archived"
        heading_blocks = [
            b for b in hub_blocks 
            if b.get("type") in ["heading1", "heading2", "heading3", "heading_1", "heading_2", "heading_3"]
        ]
    
        heading_contents = [b.get("content", "").lower() for b in heading_blocks]
    
        has_active_section = any("active" in content for content in heading_contents)
        has_archived_section = any("archived" in content for content in heading_contents)
    
        if not has_active_section:
            errors.append("[X] Projects Hub does not have 'Active Projects' section heading")
        else:
            checks_passed.append("[C] Projects Hub has 'Active Projects' section heading")
        if not has_archived_section:
            errors.append("[X] Projects Hub does not have 'Archived Projects' section heading")
        else:
            checks_passed.append("[C] Projects Hub has Active Projects and Archived Projects section headings")
    
        # Check for divider block
        has_divider = any(
            b.get("type") == "divider"
            for b in hub_blocks
        )
        if not has_divider:
            errors.append("[X] Projects Hub does not have a divider block between sections")
        else:
            checks_passed.append("[C] Projects Hub has divider block")
    
        # Check that at least 3 project-related pages are moved under Projects Hub
        child_pages = _get_child_pages(final_state_backend, projects_hub_id)
        project_children = [
            p for p in child_pages 
            if "project" in p.get("title", "").lower()
        ]
    
        if len(project_children) < 3:
            errors.append(f"[X] Expected at least 3 project pages moved under Projects Hub, found {len(project_children)}")
        else:
            checks_passed.append(f"[C] {len(project_children)} project pages moved under Projects Hub")
    
        # Check that 'Old Project Notes' is archived
        old_project_notes = _find_page_by_title(final_state_backend, "Old Project Notes")
        if not old_project_notes:
            errors.append("[X] 'Old Project Notes' page not found")
        else:
            checks_passed.append("[C] 'Old Project Notes' page found")
    
        if not old_project_notes.get("isArchived", False):
            errors.append("[X] 'Old Project Notes' page is not archived")
        else:
            checks_passed.append("[C] 'Old Project Notes' page is archived")
    
        # Verify multiple headings for organized structure
        if len(heading_blocks) < 3:
            errors.append(f"[X] Projects Hub should have multiple headings for organized structure, found {len(heading_blocks)}")
        else:
            checks_passed.append(f"[C] Projects Hub has {len(heading_blocks)} headings for organized structure")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task 11: Documentation Center Organization
# =============================================================================
def _validate_documentation_center_organization(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate documentation center organization with structured sub-pages and moved docs."""
    errors: list[str] = []

    checks_passed = []
    
    # Check for Documentation Center page with book icon
    try:
        doc_center = _find_page_by_title(final_state_backend, "Documentation Center")
        if not doc_center:
            errors.append("[X] Documentation Center page not found")
        else:
            checks_passed.append("[C] Documentation Center page found")
    
        # Check for book icon
        icon = doc_center.get("icon", "")
        if "book" not in icon.lower() and "📖" not in icon and "📚" not in icon and "📕" not in icon:
            errors.append("[X] Documentation Center does not have a book icon")
        else:
            checks_passed.append("[C] Documentation Center page created with book icon")
    
        # Check that Documentation Center is marked as favorite
        if not doc_center.get("isFavorite", False):
            errors.append("[X] Documentation Center is not marked as favorite")
        else:
            checks_passed.append("[C] Documentation Center marked as favorite")
    
        doc_center_id = doc_center.get("_id")
    
        # Check for 2 required sub-pages: Technical Docs and Process Docs
        required_subpages = ["Technical Docs", "Process Docs"]
    
        success, error, found = _validate_page_structure(final_state_backend, doc_center, required_subpages)
        if not success:
            errors.append(f"[X] {error}")
        else:
            checks_passed.append(f"[C] Check passed")
        checks_passed.append("[C] Both required sub-pages (Technical Docs, Process Docs) created")
    
        # Check that main page has welcome content (paragraph or heading)
        center_blocks = _get_blocks_for_page(final_state_backend, doc_center_id)
    
        has_welcome_content = any(
            b.get("type") in ["paragraph", "text", "heading1", "heading2", "heading_1", "heading_2"]
            for b in center_blocks
        )
        if not has_welcome_content:
            errors.append("[X] Documentation Center does not have welcome content")
        else:
            checks_passed.append("[C] Documentation Center has welcome content")
    
        # Check for callout block explaining organization
        has_callout = any(
            b.get("type") == "callout"
            for b in center_blocks
        )
        if not has_callout:
            errors.append("[X] Documentation Center does not have a callout explaining the organization system")
        else:
            checks_passed.append("[C] Documentation Center has callout explaining organization")
    
        # Check that documentation-related pages were moved under appropriate sections
        # Find pages with 'Documentation' in title (excluding the center itself)
        all_doc_pages = _find_pages_by_title(final_state_backend, "documentation")
        doc_pages = [
            p for p in all_doc_pages 
            if p.get("_id") != doc_center_id
            and "Center" not in p.get("title", "")
        ]
    
        # Get child pages of Technical Docs and Process Docs
        technical_docs = _find_child_by_title(final_state_backend, doc_center, "Technical Docs")
        process_docs = _find_child_by_title(final_state_backend, doc_center, "Process Docs")
    
        if technical_docs and process_docs:
            tech_children = _get_child_pages(final_state_backend, technical_docs.get("_id"))
            process_children = _get_child_pages(final_state_backend, process_docs.get("_id"))
        
            # If there were documentation pages to move, check they were moved
            if len(doc_pages) > 0:
                total_moved = len(tech_children) + len(process_children)
                if total_moved > 0:
                    checks_passed.append(f"[C] Documentation pages organized under appropriate sections")
                else:
                    checks_passed.append("[C] Documentation pages found but sub-page structure created")
            else:
                checks_passed.append("[C] Sub-page structure created (no existing documentation pages to move)")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task 12: Documentation Template from Weekly Standup
# =============================================================================
def _validate_documentation_template(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate documentation template created from Weekly Standup Template."""
    errors: list[str] = []

    checks_passed = []
    
    # Check for Documentation Template page with book emoji icon
    try:
        doc_template = _find_page_by_title(final_state_backend, "Documentation Template")
        if not doc_template:
            errors.append("[X] Documentation Template page not found")
        else:
            checks_passed.append("[C] Documentation Template page found")
    
        # Check for book emoji icon
        icon = doc_template.get("icon", "")
        if "book" not in icon.lower() and "📖" not in icon and "📚" not in icon and "📕" not in icon:
            errors.append("[X] Documentation Template does not have a book emoji icon")
        else:
            checks_passed.append("[C] Documentation Template page created with book emoji icon")
    
        # Check that Documentation Template is marked as favorite
        if not doc_template.get("isFavorite", False):
            errors.append("[X] Documentation Template is not marked as favorite")
        else:
            checks_passed.append("[C] Documentation Template marked as favorite")
    
        doc_template_id = doc_template.get("_id")
    
        # Check for 3 required headings: Overview, Requirements, Implementation
        template_blocks = _get_blocks_for_page(final_state_backend, doc_template_id)
    
        heading_blocks = [
            b for b in template_blocks 
            if b.get("type") in ["heading1", "heading2", "heading3", "heading_1", "heading_2", "heading_3"]
        ]
    
        heading_contents = [b.get("content", "").lower() for b in heading_blocks]
    
        required_headings = ["overview", "requirements", "implementation"]
        found_headings = []
    
        for required in required_headings:
            if any(required in content for content in heading_contents):
                found_headings.append(required)
    
        if len(found_headings) != 3:
            missing = [h for h in required_headings if h not in found_headings]
            errors.append(f"[X] Documentation Template missing headings: {', '.join(missing)}")
        else:
            checks_passed.append("[C] All 3 required headings (Overview, Requirements, Implementation) present")
    
        # Check for numbered lists (at least one)
        has_numbered_list = any(
            b.get("type") in ["numberedList", "numbered_list", "numbered_list_item", "numbered"]
            for b in template_blocks
        )
        if not has_numbered_list:
            errors.append("[X] Documentation Template does not have numbered lists under headings")
        else:
            checks_passed.append("[C] Documentation Template contains numbered lists")
    
        # Check for code block
        has_code_block = any(
            b.get("type") == "code"
            for b in template_blocks
        )
        if not has_code_block:
            errors.append("[X] Documentation Template does not have a code block")
        else:
            checks_passed.append("[C] Documentation Template contains code block")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task 13: Documentation Hub Setup
# =============================================================================
def _validate_documentation_hub_setup(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate documentation hub with sub-pages and todo checklists."""
    errors: list[str] = []

    checks_passed = []
    
    # Check for Documentation Hub page with books icon
    try:
        doc_hub = _find_page_by_title(final_state_backend, "Documentation Hub")
        if not doc_hub:
            errors.append("[X] Documentation Hub page not found")
        else:
            checks_passed.append("[C] Documentation Hub page found")
    
        # Check for books icon
        icon = doc_hub.get("icon", "")
        if "book" not in icon.lower() and "📖" not in icon and "📚" not in icon:
            errors.append("[X] Documentation Hub does not have a books icon")
        else:
            checks_passed.append("[C] Documentation Hub page created with books icon")
    
        # Check that Documentation Hub is marked as favorite
        if not doc_hub.get("isFavorite", False):
            errors.append("[X] Documentation Hub is not marked as favorite")
        else:
            checks_passed.append("[C] Documentation Hub marked as favorite")
    
        doc_hub_id = doc_hub.get("_id")
    
        # Check for callout block explaining the hub's purpose
        hub_blocks = _get_blocks_for_page(final_state_backend, doc_hub_id)
    
        has_callout = any(
            b.get("type") == "callout"
            for b in hub_blocks
        )
        if not has_callout:
            errors.append("[X] Documentation Hub does not have a callout block explaining its purpose")
        else:
            checks_passed.append("[C] Documentation Hub has callout block")
    
        # Check for exactly 3 sub-pages
        required_subpages = ["Technical Specs", "User Guides", "API References"]
    
        success, error, found = _validate_page_structure(final_state_backend, doc_hub, required_subpages)
        if not success:
            errors.append(f"[X] {error}")
        else:
            checks_passed.append(f"[C] Check passed")
        checks_passed.append("[C] All 3 required sub-pages created")
    
        # Check each sub-page has a heading and 3 todo items
        for subpage_title in required_subpages:
            subpage = _find_child_by_title(final_state_backend, doc_hub, subpage_title)
            if not subpage:
                errors.append(f"[X] Sub-page '{subpage_title}' not found")
            else:
                checks_passed.append(f"[C] Sub-page '{subpage_title}' found")
        
            subpage_id = subpage.get("_id")
            subpage_blocks = _get_blocks_for_page(final_state_backend, subpage_id)
        
            # Check for heading
            has_heading = any(
                b.get("type") in ["heading1", "heading2", "heading3", "heading_1", "heading_2", "heading_3"]
                for b in subpage_blocks
            )
            if not has_heading:
                errors.append(f"[X] Sub-page '{subpage_title}' does not have a heading")
            else:
                checks_passed.append(f"[C] Sub-page '{subpage_title}' has a heading")
        
            # Check for todo items (at least 3)
            todo_blocks = [
                b for b in subpage_blocks 
                if b.get("type") in ["todo", "to_do", "checkbox"]
            ]
            if len(todo_blocks) < 3:
                errors.append(f"[X] Sub-page '{subpage_title}' should have 3 todo items, found {len(todo_blocks)}")
            else:
                checks_passed.append(f"[C] Sub-page '{subpage_title}' should have 3 todo items, found {len(todo_blocks)}")
    
        checks_passed.append("[C] Each sub-page contains heading and 3 todo items")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task 14: Project Hub 2024 Setup
# =============================================================================
def _validate_project_hub_2024(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Project Hub 2024 with moved Project Roadmap and sub-pages."""
    errors: list[str] = []

    checks_passed = []
    
    # Check for Project Hub 2024 page with rocket icon
    try:
        project_hub = _find_page_by_title(final_state_backend, "Project Hub 2024")
        if not project_hub:
            errors.append("[X] Project Hub 2024 page not found")
        else:
            checks_passed.append("[C] Project Hub 2024 page found")
    
        # Check for rocket icon
        icon = project_hub.get("icon", "")
        if "rocket" not in icon.lower() and "🚀" not in icon:
            errors.append("[X] Project Hub 2024 does not have a rocket icon")
        else:
            checks_passed.append("[C] Project Hub 2024 page created with rocket icon")
    
        # Check that Project Hub 2024 is marked as favorite
        if not project_hub.get("isFavorite", False):
            errors.append("[X] Project Hub 2024 is not marked as favorite")
        else:
            checks_passed.append("[C] Project Hub 2024 marked as favorite")
    
        project_hub_id = project_hub.get("_id")
    
        # Check that Project Roadmap is moved under Project Hub 2024
        project_roadmap = _find_page_by_title(final_state_backend, "Project Roadmap")
        if not project_roadmap:
            errors.append("[X] Project Roadmap page not found")
        else:
            checks_passed.append("[C] Project Roadmap page found")
    
        if project_roadmap.get("parentId") != project_hub_id:
            errors.append("[X] Project Roadmap is not moved under Project Hub 2024")
        else:
            checks_passed.append("[C] Project Roadmap moved under Project Hub 2024")
    
        # Check that Q1 Goals and Q2 Goals are children of Project Roadmap
        roadmap_id = project_roadmap.get("_id")
    
        q1_goals = _find_child_by_title_with_id(final_state_backend, roadmap_id, "Q1 Goals")
        q2_goals = _find_child_by_title_with_id(final_state_backend, roadmap_id, "Q2 Goals")
    
        if not q1_goals:
            errors.append("[X] Q1 Goals sub-page not found under Project Roadmap")
        else:
            checks_passed.append("[C] Q1 Goals sub-page found under Project Roadmap")
        if not q2_goals:
            errors.append("[X] Q2 Goals sub-page not found under Project Roadmap")
        else:
            checks_passed.append("[C] Q1 Goals and Q2 Goals are children of Project Roadmap")
    
        # Check that hub page has proper content: heading, callout, numbered list
        hub_blocks = _get_blocks_for_page(final_state_backend, project_hub_id)
    
        has_heading = any(
            b.get("type") in ["heading1", "heading2", "heading3", "heading_1", "heading_2", "heading_3"]
            for b in hub_blocks
        )
        if not has_heading:
            errors.append("[X] Project Hub 2024 does not have a heading block")
        else:
            checks_passed.append("[C] Project Hub 2024 has a heading block")
    
        has_callout = any(
            b.get("type") == "callout"
            for b in hub_blocks
        )
        if not has_callout:
            errors.append("[X] Project Hub 2024 does not have a callout block")
        else:
            checks_passed.append("[C] Project Hub 2024 has a callout block")
    
        has_numbered_list = any(
            b.get("type") in ["numberedList", "numbered_list", "numbered_list_item", "numbered"]
            for b in hub_blocks
        )
        if not has_numbered_list:
            errors.append("[X] Project Hub 2024 does not have a numbered list for Quick Links")
        else:
            checks_passed.append("[C] Project Hub 2024 has a numbered list for Quick Links")
    
        checks_passed.append("[C] Hub page contains heading, callout, and numbered list blocks")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task 15: Research Repository
# =============================================================================
def _validate_research_repository(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate research repository with organized pages and template."""
    errors: list[str] = []

    checks_passed = []
    
    # Check for Research Repository page with microscope icon
    try:
        research_repo = _find_page_by_title(final_state_backend, "Research Repository")
        if not research_repo:
            errors.append("[X] Research Repository page not found")
        else:
            checks_passed.append("[C] Research Repository page found")
    
        # Check for microscope icon
        icon = research_repo.get("icon", "")
        if "microscope" not in icon.lower() and "🔬" not in icon:
            errors.append("[X] Research Repository does not have a microscope icon")
        else:
            checks_passed.append("[C] Research Repository page created with microscope icon")
    
        # Check that Research Repository is marked as favorite
        if not research_repo.get("isFavorite", False):
            errors.append("[X] Research Repository is not marked as favorite")
        else:
            checks_passed.append("[C] Research Repository marked as favorite")
    
        research_repo_id = research_repo.get("_id")
    
        # Check that at least 2 research-related pages are moved under it
        child_pages = _get_child_pages(final_state_backend, research_repo_id)
        research_children = [
            p for p in child_pages 
            if "research" in p.get("title", "").lower() or "notes" in p.get("title", "").lower()
        ]
    
        # Count non-template research pages
        non_template_research = [p for p in research_children if "template" not in p.get("title", "").lower()]
    
        if len(non_template_research) < 2:
            errors.append(f"[X] Expected at least 2 research-related pages moved under repository, found {len(non_template_research)}")
        else:
            checks_passed.append(f"[C] {len(non_template_research)} research-related pages moved under repository")
    
        # Check repository content: 2 heading1 blocks, 1 numbered list, 1 quote block
        repo_blocks = _get_blocks_for_page(final_state_backend, research_repo_id)
    
        heading1_blocks = [
            b for b in repo_blocks 
            if b.get("type") in ["heading1", "heading_1"]
        ]
        if len(heading1_blocks) < 2:
            errors.append(f"[X] Research Repository should have 2 heading1 blocks, found {len(heading1_blocks)}")
        else:
            checks_passed.append("[C] Repository has 2 heading1 blocks")
    
        has_numbered_list = any(
            b.get("type") in ["numberedList", "numbered_list", "numbered_list_item", "numbered"]
            for b in repo_blocks
        )
        if not has_numbered_list:
            errors.append("[X] Research Repository does not have a numbered list for best practices")
        else:
            checks_passed.append("[C] Repository has numbered list")
    
        has_quote = any(
            b.get("type") == "quote"
            for b in repo_blocks
        )
        if not has_quote:
            errors.append("[X] Research Repository does not have a quote block")
        else:
            checks_passed.append("[C] Repository has quote block")
    
        # Check for Research Template child page with 3 headings
        research_template = _find_child_by_title(final_state_backend, research_repo, "Research Template")
        if not research_template:
            errors.append("[X] Research Template child page not found")
        else:
            checks_passed.append("[C] Research Template child page found")
    
        template_id = research_template.get("_id")
        template_blocks = _get_blocks_for_page(final_state_backend, template_id)
    
        template_headings = [
            b for b in template_blocks 
            if b.get("type") in ["heading1", "heading2", "heading3", "heading_1", "heading_2", "heading_3"]
        ]
    
        heading_contents = [b.get("content", "").lower() for b in template_headings]
        required_headings = ["hypothesis", "methodology", "results"]
    
        found_headings = []
        for required in required_headings:
            if any(required in content for content in heading_contents):
                found_headings.append(required)
    
        if len(found_headings) < 3:
            missing = [h for h in required_headings if h not in found_headings]
            errors.append(f"[X] Research Template missing headings: {', '.join(missing)}")
        else:
            checks_passed.append("[C] Research Template has 3 required headings")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task 16: Project Planning Center
# =============================================================================
def _validate_project_planning_center(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate project planning center with duplicated templates."""
    errors: list[str] = []

    checks_passed = []
    
    # Check for Project Planning Center page with strategy icon
    try:
        planning_center = _find_page_by_title(final_state_backend, "Project Planning Center")
        if not planning_center:
            errors.append("[X] Project Planning Center page not found")
        else:
            checks_passed.append("[C] Project Planning Center page found")
    
        # Check for strategy icon (target, chess, strategy, compass)
        icon = planning_center.get("icon", "")
        valid_icons = ["strategy", "target", "chess", "compass", "🎯", "♟️", "🧭", "📋", "📊"]
        if not any(vi in icon.lower() or vi in icon for vi in valid_icons):
            errors.append("[X] Project Planning Center does not have a strategy icon")
        else:
            checks_passed.append("[C] Project Planning Center page created with strategy icon")
    
        planning_center_id = planning_center.get("_id")
    
        # Check for Q1 Project Template and Sprint Planning Template as children
        q1_template = _find_child_by_title(final_state_backend, planning_center, "Q1 Project Template")
        sprint_template = _find_child_by_title(final_state_backend, planning_center, "Sprint Planning Template")
    
        if not q1_template:
            errors.append("[X] Q1 Project Template not found under Project Planning Center")
        else:
            checks_passed.append("[C] Q1 Project Template found under Project Planning Center")
        if not sprint_template:
            errors.append("[X] Sprint Planning Template not found under Project Planning Center")
        else:
            checks_passed.append("[C] Both template pages created and organized under center")
    
        # Check that center has planning guidelines with numbered steps
        center_blocks = _get_blocks_for_page(final_state_backend, planning_center_id)
    
        has_numbered_list = any(
            b.get("type") in ["numberedList", "numbered_list", "numbered_list_item", "numbered"]
            for b in center_blocks
        )
        if not has_numbered_list:
            errors.append("[X] Project Planning Center does not have numbered steps for planning guidelines")
        else:
            checks_passed.append("[C] Center contains planning guidelines with numbered steps")
    
        # Check for callout highlighting best practices
        has_callout = any(
            b.get("type") == "callout"
            for b in center_blocks
        )
        if not has_callout:
            errors.append("[X] Project Planning Center does not have a best practices callout")
        else:
            checks_passed.append("[C] Center has best practices callout")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task 17: Learning & Development Hub
# =============================================================================
def _validate_learning_development_hub(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate learning & development hub with structured content."""
    errors: list[str] = []

    checks_passed = []
    
    # Check for Learning & Development Hub page with graduation cap icon
    try:
        learning_hub = _find_page_by_title(final_state_backend, "Learning & Development Hub")
        if not learning_hub:
            # Try alternative names
            learning_hub = _find_page_by_title(final_state_backend, "Learning and Development Hub")
        if not learning_hub:
            learning_hub = _find_page_by_title(final_state_backend, "Learning Development Hub")
        if not learning_hub:
            errors.append("[X] Learning & Development Hub page not found")
        else:
            checks_passed.append("[C] Learning & Development Hub page found")
    
        # Check for graduation cap icon
        icon = learning_hub.get("icon", "")
        if "graduation" not in icon.lower() and "🎓" not in icon and "cap" not in icon.lower():
            errors.append("[X] Learning & Development Hub does not have a graduation cap icon")
        else:
            checks_passed.append("[C] Learning & Development Hub page created with graduation cap icon")
    
        # Check that hub is marked as favorite
        if not learning_hub.get("isFavorite", False):
            errors.append("[X] Learning & Development Hub is not marked as favorite")
        else:
            checks_passed.append("[C] Learning & Development Hub marked as favorite")
    
        learning_hub_id = learning_hub.get("_id")
    
        # Check for exactly 3 child pages
        required_subpages = ["Technical Skills", "Soft Skills", "Company Knowledge"]
    
        success, error, found = _validate_page_structure(final_state_backend, learning_hub, required_subpages)
        if not success:
            errors.append(f"[X] {error}")
        else:
            checks_passed.append(f"[C] Check passed")
        checks_passed.append("[C] All 3 required sub-pages created")
    
        # Check Technical Skills page: 2 headings, bulleted list with 4 items, numbered list with 5 items
        tech_skills = _find_child_by_title(final_state_backend, learning_hub, "Technical Skills")
        if tech_skills:
            tech_id = tech_skills.get("_id")
            tech_blocks = _get_blocks_for_page(final_state_backend, tech_id)
        
            tech_headings = [
                b for b in tech_blocks 
                if b.get("type") in ["heading1", "heading2", "heading3", "heading_1", "heading_2", "heading_3"]
            ]
            if len(tech_headings) < 2:
                errors.append(f"[X] Technical Skills should have 2 headings, found {len(tech_headings)}")
            else:
                checks_passed.append(f"[C] Technical Skills should have 2 headings, found {len(tech_headings)}")
        
            bulleted_items = [
                b for b in tech_blocks 
                if b.get("type") in ["bulletedList", "bulleted_list", "bulleted_list_item", "bulleted"]
            ]
            if len(bulleted_items) < 4:
                errors.append(f"[X] Technical Skills should have bulleted list with 4 items, found {len(bulleted_items)}")
            else:
                checks_passed.append(f"[C] Technical Skills should have bulleted list with 4 items, found {len(bulleted_items)}")
        
            numbered_items = [
                b for b in tech_blocks 
                if b.get("type") in ["numberedList", "numbered_list", "numbered_list_item", "numbered"]
            ]
            if len(numbered_items) < 5:
                errors.append(f"[X] Technical Skills should have numbered list with 5 items, found {len(numbered_items)}")
            else:
                checks_passed.append(f"[C] Technical Skills should have numbered list with 5 items, found {len(numbered_items)}")
    
        checks_passed.append("[C] Technical Skills has 2 headings, bulleted list (4 items), numbered list (5 items)")
    
        # Check Soft Skills page: heading and todo checklist with 5 items
        soft_skills = _find_child_by_title(final_state_backend, learning_hub, "Soft Skills")
        if soft_skills:
            soft_id = soft_skills.get("_id")
            soft_blocks = _get_blocks_for_page(final_state_backend, soft_id)
        
            has_heading = any(
                b.get("type") in ["heading1", "heading2", "heading3", "heading_1", "heading_2", "heading_3"]
                for b in soft_blocks
            )
            if not has_heading:
                errors.append("[X] Soft Skills does not have a heading")
            else:
                checks_passed.append("[C] Soft Skills has a heading")
        
            todo_items = [
                b for b in soft_blocks 
                if b.get("type") in ["todo", "to_do", "checkbox"]
            ]
            if len(todo_items) < 5:
                errors.append(f"[X] Soft Skills should have todo checklist with 5 items, found {len(todo_items)}")
            else:
                checks_passed.append(f"[C] Soft Skills should have todo checklist with 5 items, found {len(todo_items)}")
    
        checks_passed.append("[C] Soft Skills has heading and todo checklist with 5 items")
    
        # Check main hub has paragraph and callout
        hub_blocks = _get_blocks_for_page(final_state_backend, learning_hub_id)
    
        has_paragraph = any(
            b.get("type") in ["paragraph", "text"]
            for b in hub_blocks
        )
        if not has_paragraph:
            errors.append("[X] Learning & Development Hub does not have an introduction paragraph")
        else:
            checks_passed.append("[C] Learning & Development Hub has an introduction paragraph")
    
        has_callout = any(
            b.get("type") == "callout"
            for b in hub_blocks
        )
        if not has_callout:
            errors.append("[X] Learning & Development Hub does not have a callout explaining learning paths")
        else:
            checks_passed.append("[C] Learning & Development Hub has a callout explaining learning paths")
    
        checks_passed.append("[C] Main hub has paragraph and callout")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task 18: Product Documentation Suite
# =============================================================================
def _validate_product_documentation_suite(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate product documentation suite with moved pages and structured content."""
    errors: list[str] = []

    checks_passed = []
    
    # Check for Product Documentation Suite page with package icon
    try:
        doc_suite = _find_page_by_title(final_state_backend, "Product Documentation Suite")
        if not doc_suite:
            errors.append("[X] Product Documentation Suite page not found")
        else:
            checks_passed.append("[C] Product Documentation Suite page found")
    
        # Check for package icon
        icon = doc_suite.get("icon", "")
        if "package" not in icon.lower() and "📦" not in icon and "box" not in icon.lower():
            errors.append("[X] Product Documentation Suite does not have a package icon")
        else:
            checks_passed.append("[C] Product Documentation Suite page created with package icon")
    
        # Check that suite is marked as favorite
        if not doc_suite.get("isFavorite", False):
            errors.append("[X] Product Documentation Suite is not marked as favorite")
        else:
            checks_passed.append("[C] Product Documentation Suite marked as favorite")
    
        doc_suite_id = doc_suite.get("_id")
    
        # Check that Product Specs and API Documentation are moved under suite
        product_specs = _find_child_by_title(final_state_backend, doc_suite, "Product Specs")
        api_docs = _find_child_by_title(final_state_backend, doc_suite, "API Documentation")
    
        if not product_specs:
            errors.append("[X] Product Specs page not found under Product Documentation Suite")
        else:
            checks_passed.append("[C] Product Specs page found under Product Documentation Suite")
        if not api_docs:
            errors.append("[X] API Documentation page not found under Product Documentation Suite")
        else:
            checks_passed.append("[C] Product Specs and API Documentation moved under suite")
    
        # Check for Integration Examples sub-page with puzzle icon
        integration_examples = _find_child_by_title(final_state_backend, doc_suite, "Integration Examples")
        if not integration_examples:
            errors.append("[X] Integration Examples sub-page not found")
        else:
            checks_passed.append("[C] Integration Examples sub-page found")
    
        integration_icon = integration_examples.get("icon", "")
        if "puzzle" not in integration_icon.lower() and "🧩" not in integration_icon:
            errors.append("[X] Integration Examples does not have a puzzle icon")
        else:
            checks_passed.append("[C] Integration Examples sub-page created with puzzle icon")
    
        # Check main page content: heading1, paragraph, bulleted list, callout
        suite_blocks = _get_blocks_for_page(final_state_backend, doc_suite_id)
    
        has_heading1 = any(
            b.get("type") in ["heading1", "heading_1"]
            for b in suite_blocks
        )
        if not has_heading1:
            errors.append("[X] Product Documentation Suite does not have a heading1 block")
        else:
            checks_passed.append("[C] Product Documentation Suite has a heading1 block")
    
        has_paragraph = any(
            b.get("type") in ["paragraph", "text"]
            for b in suite_blocks
        )
        if not has_paragraph:
            errors.append("[X] Product Documentation Suite does not have a paragraph block")
        else:
            checks_passed.append("[C] Product Documentation Suite has a paragraph block")
    
        has_bulleted_list = any(
            b.get("type") in ["bulletedList", "bulleted_list", "bulleted_list_item", "bulleted"]
            for b in suite_blocks
        )
        if not has_bulleted_list:
            errors.append("[X] Product Documentation Suite does not have a bulleted list of sections")
        else:
            checks_passed.append("[C] Product Documentation Suite has a bulleted list of sections")
    
        has_callout = any(
            b.get("type") == "callout"
            for b in suite_blocks
        )
        if not has_callout:
            errors.append("[X] Product Documentation Suite does not have a callout highlighting updates")
        else:
            checks_passed.append("[C] Product Documentation Suite has a callout highlighting updates")
    
        checks_passed.append("[C] Main page contains heading1, paragraph, bulletedList, and callout blocks")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task 19: Engineering Wiki Consolidation
# =============================================================================
def _validate_engineering_wiki_consolidation(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate engineering wiki consolidation with new sub-pages."""
    errors: list[str] = []

    checks_passed = []
    
    # Check for Engineering Wiki page
    try:
        eng_wiki = _find_page_by_title(final_state_backend, "Engineering Wiki")
        if not eng_wiki:
            errors.append("[X] Engineering Wiki page not found")
        else:
            checks_passed.append("[C] Engineering Wiki page found")
    
        eng_wiki_id = eng_wiki.get("_id")
    
        # Check for 3 required sub-pages
        required_subpages = ["Setup Guide", "Best Practices", "Troubleshooting"]
    
        success, error, found = _validate_page_structure(final_state_backend, eng_wiki, required_subpages)
        if not success:
            errors.append(f"[X] {error}")
        else:
            checks_passed.append(f"[C] Check passed")
        checks_passed.append("[C] All 3 required sub-pages created")
    
        # Check each sub-page has heading1, paragraph, and todo blocks
        for subpage_title in required_subpages:
            subpage = _find_child_by_title(final_state_backend, eng_wiki, subpage_title)
            if not subpage:
                errors.append(f"[X] Sub-page '{subpage_title}' not found")
            else:
                checks_passed.append(f"[C] Sub-page '{subpage_title}' found")
        
            subpage_id = subpage.get("_id")
            subpage_blocks = _get_blocks_for_page(final_state_backend, subpage_id)
        
            has_heading1 = any(
                b.get("type") in ["heading1", "heading_1"]
                for b in subpage_blocks
            )
            if not has_heading1:
                errors.append(f"[X] Sub-page '{subpage_title}' does not have a heading1 block")
            else:
                checks_passed.append(f"[C] Sub-page '{subpage_title}' has a heading1 block")
        
            has_paragraph = any(
                b.get("type") in ["paragraph", "text"]
                for b in subpage_blocks
            )
            if not has_paragraph:
                errors.append(f"[X] Sub-page '{subpage_title}' does not have a paragraph block")
            else:
                checks_passed.append(f"[C] Sub-page '{subpage_title}' has a paragraph block")
        
            has_todo = any(
                b.get("type") in ["todo", "to_do", "checkbox"]
                for b in subpage_blocks
            )
            if not has_todo:
                errors.append(f"[X] Sub-page '{subpage_title}' does not have todo blocks")
            else:
                checks_passed.append(f"[C] Sub-page '{subpage_title}' has todo blocks")
    
        checks_passed.append("[C] Each child page contains heading1, paragraph, and todo blocks")
    
        # Check Engineering Wiki has new heading1 and bulleted list
        wiki_blocks = _get_blocks_for_page(final_state_backend, eng_wiki_id)
    
        has_heading1 = any(
            b.get("type") in ["heading1", "heading_1"]
            for b in wiki_blocks
        )
        if not has_heading1:
            errors.append("[X] Engineering Wiki does not have a heading1 block")
        else:
            checks_passed.append("[C] Engineering Wiki has a heading1 block")
    
        has_bulleted_list = any(
            b.get("type") in ["bulletedList", "bulleted_list", "bulleted_list_item", "bulleted"]
            for b in wiki_blocks
        )
        if not has_bulleted_list:
            errors.append("[X] Engineering Wiki does not have a bulleted list linking to sections")
        else:
            checks_passed.append("[C] Engineering Wiki has a bulleted list linking to sections")
    
        checks_passed.append("[C] Engineering Wiki updated with heading1 and bulletedList blocks")
    
        # Verify proper parent-child hierarchy
        child_pages = _get_child_pages(final_state_backend, eng_wiki_id)
        child_count = len([p for p in child_pages if p.get("title", "") in required_subpages or any(req.lower() in p.get("title", "").lower() for req in required_subpages)])
    
        if child_count < 3:
            errors.append(f"[X] Not all pages maintain proper parent-child hierarchy under Engineering Wiki")
        else:
            checks_passed.append("[C] All pages maintain proper parent-child hierarchy")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task 20: Development Priorities Overview
# =============================================================================
def _validate_development_priorities(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate development priorities page with aggregated unchecked todos from Bug Tracker and Feature Requests."""
    errors: list[str] = []

    checks_passed = []
    
    # Check for Development Priorities page with target icon
    try:
        dev_priorities = _find_page_by_title(final_state_backend, "Development Priorities")
        if not dev_priorities:
            errors.append("[X] Development Priorities page not found")
        else:
            checks_passed.append("[C] Development Priorities page found")
    
        # Check for target icon (🎯)
        icon = dev_priorities.get("icon", "")
        if "target" not in icon.lower() and "🎯" not in icon:
            errors.append("[X] Development Priorities does not have a 🎯 (target) icon")
        else:
            checks_passed.append("[C] Development Priorities page created with 🎯 icon")
    
        dev_priorities_id = dev_priorities.get("_id")
    
        # Find Bug Tracker and Feature Requests pages
        bug_tracker = _find_page_by_title(final_state_backend, "Bug Tracker")
        feature_requests = _find_page_by_title(final_state_backend, "Feature Requests")
    
        if not bug_tracker:
            errors.append("[X] Bug Tracker page not found")
        else:
            checks_passed.append("[C] Bug Tracker page found")
        if not feature_requests:
            errors.append("[X] Feature Requests page not found")
        else:
            checks_passed.append("[C] Bug Tracker and Feature Requests pages found")
    
        # Count unchecked todos from Bug Tracker - using query-level filtering
        bug_tracker_id = bug_tracker.get("_id")
        unchecked_bugs = [
            b for b in _get_todo_blocks(final_state_backend, bug_tracker_id)
            if not b.get("checked", False)
            and not b.get("properties", {}).get("checked", False)
        ]
    
        # Count unchecked todos from Feature Requests - using query-level filtering
        feature_requests_id = feature_requests.get("_id")
        unchecked_features = [
            b for b in _get_todo_blocks(final_state_backend, feature_requests_id)
            if not b.get("checked", False)
            and not b.get("properties", {}).get("checked", False)
        ]
    
        total_unchecked = len(unchecked_bugs) + len(unchecked_features)
        checks_passed.append(f"[C] Found {len(unchecked_bugs)} unchecked bugs and {len(unchecked_features)} unchecked features (total: {total_unchecked})")
    
        # Get blocks for Development Priorities page
        priority_blocks = _get_blocks_for_page(final_state_backend, dev_priorities_id)
    
        # Check for main heading with correct count: "Critical Items ([total count] pending)"
        heading_blocks = [
            b for b in priority_blocks
            if b.get("type") in ["heading1", "heading_1"]
        ]
    
        found_critical_heading = False
        for heading in heading_blocks:
            content = heading.get("content", "").lower()
            if "critical" in content and "pending" in content:
                # Check if the count is mentioned
                if str(total_unchecked) in heading.get("content", ""):
                    found_critical_heading = True
                    break
    
        if not found_critical_heading:
            # Allow some flexibility - just check for "critical" and "pending" in any heading
            for heading in heading_blocks:
                content = heading.get("content", "").lower()
                if "critical" in content and "pending" in content:
                    found_critical_heading = True
                    break
    
        if not found_critical_heading:
            errors.append(f"[X] Development Priorities does not have a heading 'Critical Items ([count] pending)'")
        else:
            checks_passed.append("[C] Main heading with 'Critical Items' and 'pending' found")
    
        # Check for two heading2 sections: 'Bugs' and 'Features'
        heading2_blocks = [
            b for b in priority_blocks
            if b.get("type") in ["heading2", "heading_2"]
        ]
    
        heading2_contents = [b.get("content", "").lower() for b in heading2_blocks]
    
        has_bugs_section = any("bug" in content for content in heading2_contents)
        has_features_section = any("feature" in content for content in heading2_contents)
    
        if not has_bugs_section:
            errors.append("[X] Development Priorities does not have a 'Bugs' heading2 section")
        else:
            checks_passed.append("[C] Development Priorities has a 'Bugs' heading2 section")
        if not has_features_section:
            errors.append("[X] Development Priorities does not have a 'Features' heading2 section")
        else:
            checks_passed.append("[C] Both 'Bugs' and 'Features' heading2 sections exist")
    
        # Check that todo items exist in the Development Priorities page
        priority_todos = [
            b for b in priority_blocks
            if b.get("type") in ["todo", "to_do", "checkbox"]
        ]
    
        # Verify unchecked todos are copied (should have todos if source pages had unchecked items)
        if total_unchecked > 0 and len(priority_todos) == 0:
            errors.append("[X] Development Priorities should have todo items copied from source pages")
        else:
            checks_passed.append("[C] Development Priorities should have todo items copied from source pages")
    
        # Check that only unchecked todos were copied (all todos in priority page should be unchecked)
        checked_in_priority = [
            b for b in priority_todos
            if b.get("checked", False) or b.get("properties", {}).get("checked", False)
        ]
        if len(checked_in_priority) > 0:
            errors.append("[X] Development Priorities should only contain unchecked todo items")
        else:
            checks_passed.append("[C] Development Priorities should only contain unchecked todo items")
    
        checks_passed.append(f"[C] Todo items copied correctly ({len(priority_todos)} unchecked todos)")
    
        # Check for red callout if total count > 5
        if total_unchecked > 5:
            callout_blocks = [
                b for b in priority_blocks
                if b.get("type") == "callout"
            ]
        
            if len(callout_blocks) == 0:
                errors.append(f"[X] Total unchecked items ({total_unchecked}) exceeds 5, but no warning callout found")
            else:
                checks_passed.append(f"[C] Total unchecked items ({total_unchecked}) exceeds 5, but warning callout found")
        
            # Check for red color in callout
            found_red_callout = False
            for callout in callout_blocks:
                color = callout.get("color", "")
                bg_color = callout.get("backgroundColor", "")
                properties = callout.get("properties", {})
                prop_color = properties.get("color", "")
                prop_bg = properties.get("backgroundColor", "")
            
                if any("red" in c.lower() for c in [color, bg_color, prop_color, prop_bg] if c):
                    found_red_callout = True
                    break
                # Also check content for backlog-related warning
                content = callout.get("content", "").lower()
                if "backlog" in content or "warning" in content or "attention" in content:
                    found_red_callout = True
                    break
        
            if not found_red_callout:
                errors.append(f"[X] Total unchecked items ({total_unchecked}) exceeds 5, but callout is not red or doesn't warn about backlog")
            else:
                checks_passed.append(f"[C] Total unchecked items ({total_unchecked}) exceeds 5, but callout is red or doesn't warn about backlog")
        
            checks_passed.append("[C] Red callout warning about backlog size present (count > 5)")
        else:
            # If count <= 5, callout is optional but shouldn't be required
            checks_passed.append(f"[C] Total count ({total_unchecked}) <= 5, red callout not required")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task 21: Weekly Sprint Dashboard
# =============================================================================
def _validate_weekly_sprint_dashboard(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Weekly Sprint Dashboard with structured daily standups and metrics."""
    errors: list[str] = []

    checks_passed = []
    
    # Check for Meeting Notes parent page
    try:
        meeting_notes = _find_page_by_title(final_state_backend, "Meeting Notes")
        if not meeting_notes:
            errors.append("[X] Meeting Notes page not found")
        else:
            checks_passed.append("[C] Meeting Notes page found")
    
        meeting_notes_id = meeting_notes.get("_id")
    
        # Check for Weekly Sprint Dashboard page as child of Meeting Notes
        sprint_dashboard = _find_page_by_title(final_state_backend, "Weekly Sprint Dashboard")
        if not sprint_dashboard:
            errors.append("[X] Weekly Sprint Dashboard page not found")
        else:
            checks_passed.append("[C] Weekly Sprint Dashboard page found")
    
        # Verify it's a child of Meeting Notes
        if sprint_dashboard.get("parentId") != meeting_notes_id:
            errors.append("[X] Weekly Sprint Dashboard is not a child of Meeting Notes")
        else:
            checks_passed.append("[C] Weekly Sprint Dashboard created under Meeting Notes")
    
        sprint_dashboard_id = sprint_dashboard.get("_id")
        dashboard_blocks = _get_blocks_for_page(final_state_backend, sprint_dashboard_id)
    
        # Check for heading_1 '🚀 Sprint Week Dashboard'
        heading1_blocks = [
            b for b in dashboard_blocks 
            if b.get("type") in ["heading1", "heading_1"]
        ]
    
        found_main_heading = False
        for h in heading1_blocks:
            content = h.get("content", "")
            if "🚀" in content and "sprint" in content.lower() and "dashboard" in content.lower():
                found_main_heading = True
                break
    
        if not found_main_heading:
            errors.append("[X] Missing heading_1 '🚀 Sprint Week Dashboard'")
        else:
            checks_passed.append("[C] Main heading '🚀 Sprint Week Dashboard' present")
    
        # Check for heading_2 '📅 Daily Standup Tracker'
        heading2_blocks = [
            b for b in dashboard_blocks 
            if b.get("type") in ["heading2", "heading_2"]
        ]
    
        found_standup_heading = False
        for h in heading2_blocks:
            content = h.get("content", "")
            if "📅" in content and "daily" in content.lower() and "standup" in content.lower():
                found_standup_heading = True
                break
    
        if not found_standup_heading:
            errors.append("[X] Missing heading_2 '📅 Daily Standup Tracker'")
        else:
            checks_passed.append("[C] Daily Standup Tracker heading_2 present")
    
        # Check for 5 weekday heading_3 blocks (Monday through Friday)
        heading3_blocks = [
            b for b in dashboard_blocks 
            if b.get("type") in ["heading3", "heading_3"]
        ]
    
        weekdays = ["monday", "tuesday", "wednesday", "thursday", "friday"]
        found_weekdays = []
    
        for h in heading3_blocks:
            content = h.get("content", "").lower()
            if "📌" in h.get("content", ""):
                for day in weekdays:
                    if day in content:
                        found_weekdays.append(day)
                        break
    
        if len(found_weekdays) < 5:
            missing = [d for d in weekdays if d not in found_weekdays]
            errors.append(f"[X] Missing weekday heading_3 blocks for: {', '.join(missing)}")
        else:
            checks_passed.append("[C] All 5 weekday heading_3 blocks present with 📌 emoji")
    
        # Check for todo blocks (should have 15 total: 3 per weekday × 5 days)
        todo_blocks = [
            b for b in dashboard_blocks 
            if b.get("type") in ["todo", "to_do", "checkbox"]
        ]
    
        if len(todo_blocks) < 15:
            errors.append(f"[X] Expected at least 15 todo blocks (3 per weekday), found {len(todo_blocks)}")
        else:
            checks_passed.append(f"[C] Found at least 15 todo blocks (3 per weekday) ({len(todo_blocks)})")
    
        # Check for specific todo content with emojis
        todo_contents = [b.get("content", "") for b in todo_blocks]
    
        required_todo_texts = ["🔨", "🐛", "📝"]
        required_todo_keywords = ["development", "bug", "documentation"]
    
        for emoji, keyword in zip(required_todo_texts, required_todo_keywords):
            count = sum(1 for c in todo_contents if emoji in c and keyword in c.lower())
            if count < 5:  # Should appear 5 times (once per weekday)
                errors.append(f"[X] Expected 5 todo items with '{emoji}' and '{keyword}', found {count}")
            else:
                checks_passed.append(f"[C] Found 5 todo items with '{emoji}' and '{keyword}' as expected")
    
        # Check that todos are unchecked
        checked_todos = [
            b for b in todo_blocks
            if b.get("checked", False) or b.get("properties", {}).get("checked", False)
        ]
        if len(checked_todos) > 0:
            errors.append("[X] Todo blocks should be unchecked")
        else:
            checks_passed.append("[C] Todo blocks should be unchecked")
    
        checks_passed.append("[C] 15 unchecked todo blocks with correct emojis present")
    
        # Check for divider block
        divider_blocks = [
            b for b in dashboard_blocks 
            if b.get("type") == "divider"
        ]
        if len(divider_blocks) == 0:
            errors.append("[X] Missing divider block after Friday")
        else:
            checks_passed.append("[C] Divider block present")
    
        # Check for heading_2 '📊 Sprint Metrics'
        found_metrics_heading = False
        for h in heading2_blocks:
            content = h.get("content", "")
            if "📊" in content and "sprint" in content.lower() and "metrics" in content.lower():
                found_metrics_heading = True
                break
    
        if not found_metrics_heading:
            errors.append("[X] Missing heading_2 '📊 Sprint Metrics'")
        else:
            checks_passed.append("[C] Sprint Metrics heading_2 present")
    
        # Check for callout with brown background
        callout_blocks = [
            b for b in dashboard_blocks 
            if b.get("type") == "callout"
        ]
    
        if len(callout_blocks) == 0:
            errors.append("[X] Missing callout block for Sprint Statistics")
        else:
            checks_passed.append("[C] has callout block for Sprint Statistics")
    
        found_brown_callout = False
        for callout in callout_blocks:
            bg_color = callout.get("backgroundColor", "")
            properties = callout.get("properties", {})
            prop_bg = properties.get("backgroundColor", "")
            color = callout.get("color", "")
            prop_color = properties.get("color", "")
        
            # Check for brown background
            if any("brown" in c.lower() for c in [bg_color, prop_bg, color, prop_color] if c):
                found_brown_callout = True
            
                # Check for no icon (icon should be empty/null/none)
                icon = callout.get("icon", "") or properties.get("icon", "")
                if icon and icon.strip():
                    # Icon exists but should be empty - this is acceptable if explicitly set to empty string
                    pass
                break
    
        if not found_brown_callout:
            errors.append("[X] Callout block does not have brown background")
        else:
            checks_passed.append("[C] Brown background callout present")
    
        # Check for heading_3 'Sprint Statistics' (could be inside callout or after it)
        found_stats_heading = False
        for h in heading3_blocks:
            content = h.get("content", "")
            if "sprint" in content.lower() and "statistics" in content.lower():
                found_stats_heading = True
                break
    
        if not found_stats_heading:
            errors.append("[X] Missing heading_3 'Sprint Statistics'")
        else:
            checks_passed.append("[C] Sprint Statistics heading_3 present")
    
        # Check for bulleted list with specific metrics
        bulleted_blocks = [
            b for b in dashboard_blocks 
            if b.get("type") in ["bulletedList", "bulleted_list", "bulleted_list_item", "bulleted"]
        ]
    
        if len(bulleted_blocks) < 4:
            errors.append(f"[X] Expected at least 4 bulleted list items for metrics, found {len(bulleted_blocks)}")
        else:
            checks_passed.append(f"[C] Found at least 4 bulleted list items for metrics ({len(bulleted_blocks)})")
    
        bulleted_contents = " ".join([b.get("content", "").lower() for b in bulleted_blocks])
    
        required_metrics = [
            ("total tasks", "15"),
            ("completed", "0"),
            ("blocked", "0"),
            ("velocity", "pending")
        ]
    
        for metric_key, metric_value in required_metrics:
            if metric_key not in bulleted_contents:
                errors.append(f"[X] Missing metric '{metric_key}' in bulleted list")
            else:
                checks_passed.append(f"[C] has metric '{metric_key}' in bulleted list")
    
        checks_passed.append("[C] All 4 sprint metrics present in bulleted list")
    
        # Check for quote block with motivational text
        quote_blocks = [
            b for b in dashboard_blocks 
            if b.get("type") == "quote"
        ]
    
        if len(quote_blocks) == 0:
            errors.append("[X] Missing quote block at the end")
        else:
            checks_passed.append("[C] has quote block at the end")
    
        found_motivational_quote = False
        for quote in quote_blocks:
            content = quote.get("content", "").lower()
            if "success" in content and "small efforts" in content and "day" in content:
                found_motivational_quote = True
                break
    
        if not found_motivational_quote:
            errors.append("[X] Quote block does not contain the expected motivational text")
        else:
            checks_passed.append("[C] Motivational quote block present")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task 22: Engineering Wiki Content Enhancement
# =============================================================================
def _validate_engineering_wiki_content_enhancement(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Engineering Wiki content enhancement with Tool Versions, code blocks, and Quick Commands."""
    errors: list[str] = []

    checks_passed = []
    
    # Check for Engineering Wiki page
    try:
        eng_wiki = _find_page_by_title(final_state_backend, "Engineering Wiki")
        if not eng_wiki:
            errors.append("[X] Engineering Wiki page not found")
        else:
            checks_passed.append("[C] Engineering Wiki page found")
    
        eng_wiki_id = eng_wiki.get("_id")
        wiki_blocks = _get_blocks_for_page(final_state_backend, eng_wiki_id)
        checks_passed.append("[C] Engineering Wiki page found")
    
        # Sort blocks by order for position validation
        sorted_blocks = sorted(wiki_blocks, key=lambda b: b.get("order", 0))
    
        # 1. Check for heading3 '🔧 Tool Versions' after Tech Stack bullets but before Development Setup
        heading3_blocks = [
            b for b in wiki_blocks 
            if b.get("type") in ["heading3", "heading_3"]
        ]
    
        tool_versions_heading = None
        for h in heading3_blocks:
            content = h.get("content", "")
            if "tool versions" in content.lower() or "🔧" in content:
                tool_versions_heading = h
                break
    
        if not tool_versions_heading:
            errors.append("[X] Missing heading3 '🔧 Tool Versions'")
        else:
            checks_passed.append("[C] Tool Versions heading3 present")
    
        # 2. Check for green callout with info icon containing version list
        callout_blocks = [
            b for b in wiki_blocks 
            if b.get("type") == "callout"
        ]
    
        found_green_versions_callout = False
        for callout in callout_blocks:
            bg_color = callout.get("backgroundColor", "")
            properties = callout.get("properties", {})
            prop_bg = properties.get("backgroundColor", "")
            content = callout.get("content", "").lower()
            icon = callout.get("icon", "") or properties.get("icon", "")
        
            # Check for green background
            is_green = any("green" in c.lower() for c in [bg_color, prop_bg] if c)
        
            # Check content for version info
            has_react = "react" in content and "v18" in content
            has_typescript = "typescript" in content and "v5" in content
            has_node = "node" in content and "v20" in content
        
            # Check for info icon
            has_info_icon = "ℹ️" in icon or "info" in icon.lower()
        
            if is_green and has_react and has_typescript and has_node:
                found_green_versions_callout = True
                if has_info_icon:
                    checks_passed.append("[C] Green callout with info icon (ℹ️) containing version list present")
                else:
                    checks_passed.append("[C] Green callout containing version list present (info icon optional)")
                break
    
        if not found_green_versions_callout:
            errors.append("[X] Missing green callout with React, TypeScript, and Node.js versions")
        else:
            checks_passed.append("[C] has green callout with React, TypeScript, and Node.js versions")
    
        # 3. Check for bash code block after Environment Variables section
        code_blocks = [
            b for b in wiki_blocks 
            if b.get("type") == "code"
        ]
    
        found_bash_env_code = False
        for code_block in code_blocks:
            content = code_block.get("content", "")
            properties = code_block.get("properties", {})
            language = properties.get("language", "").lower()
        
            # Check for bash language and environment variables content
            has_database_url = "database_url" in content.lower() or "DATABASE_URL" in content
            has_api_key = "api_key" in content.lower() or "API_KEY" in content
            has_jwt_secret = "jwt_secret" in content.lower() or "JWT_SECRET" in content
            has_port = "port" in content.lower() or "PORT" in content
        
            if has_database_url and has_api_key and has_jwt_secret and has_port:
                found_bash_env_code = True
                if language == "bash":
                    checks_passed.append("[C] Bash code block with environment variables present")
                else:
                    checks_passed.append("[C] Code block with environment variables present")
                break
    
        if not found_bash_env_code:
            errors.append("[X] Missing bash code block with DATABASE_URL, API_KEY, JWT_SECRET, and PORT")
        else:
            checks_passed.append("[C] has bash code block with DATABASE_URL, API_KEY, JWT_SECRET, and PORT")
    
        # 4. Check for yellow warning callout about prerequisites
        found_yellow_prereq_callout = False
        for callout in callout_blocks:
            bg_color = callout.get("backgroundColor", "")
            properties = callout.get("properties", {})
            prop_bg = properties.get("backgroundColor", "")
            content = callout.get("content", "").lower()
            icon = callout.get("icon", "") or properties.get("icon", "")
        
            # Check for yellow background
            is_yellow = any("yellow" in c.lower() for c in [bg_color, prop_bg] if c)
        
            # Check content for prerequisites
            has_prereq = "prerequisite" in content or "node.js" in content and "mongodb" in content
        
            # Check for warning icon
            has_warning_icon = "⚠️" in icon or "warning" in icon.lower()
        
            if is_yellow and has_prereq:
                found_yellow_prereq_callout = True
                if has_warning_icon:
                    checks_passed.append("[C] Yellow callout with warning icon (⚠️) about prerequisites present")
                else:
                    checks_passed.append("[C] Yellow callout about prerequisites present (warning icon optional)")
                break
    
        if not found_yellow_prereq_callout:
            errors.append("[X] Missing yellow callout with prerequisites warning about Node.js and MongoDB")
        else:
            checks_passed.append("[C] has yellow callout with prerequisites warning about Node.js and MongoDB")
    
        # 5. Check for heading2 '🔍 Quick Commands' at the end
        heading2_blocks = [
            b for b in wiki_blocks 
            if b.get("type") in ["heading2", "heading_2"]
        ]
    
        found_quick_commands_heading = False
        for h in heading2_blocks:
            content = h.get("content", "")
            if "quick commands" in content.lower() or "🔍" in content:
                found_quick_commands_heading = True
                break
    
        if not found_quick_commands_heading:
            errors.append("[X] Missing heading2 '🔍 Quick Commands'")
        else:
            checks_passed.append("[C] Quick Commands heading2 present")
    
        # 6. Check for JSON code block with npm scripts
        found_json_commands_code = False
        for code_block in code_blocks:
            content = code_block.get("content", "")
            properties = code_block.get("properties", {})
            language = properties.get("language", "").lower()
        
            # Check for npm scripts content
            has_start = "start" in content and "npm run dev" in content
            has_test = "test" in content and "npm test" in content
            has_build = "build" in content and "npm run build" in content
            has_lint = "lint" in content and "npm run lint" in content
        
            if has_start and has_test and has_build and has_lint:
                found_json_commands_code = True
                if language == "json":
                    checks_passed.append("[C] JSON code block with npm scripts present")
                else:
                    checks_passed.append("[C] Code block with npm scripts present")
                break
    
        if not found_json_commands_code:
            errors.append("[X] Missing JSON code block with start, test, build, and lint npm scripts")
        else:
            checks_passed.append("[C] has JSON code block with start, test, build, and lint npm scripts")
    
        # 7. Validate block ordering (Tool Versions should be after Tech Stack, before Development Setup)
        # Find the order values for key blocks
        tech_stack_order = None
        dev_setup_order = None
        tool_versions_order = tool_versions_heading.get("order", 0) if tool_versions_heading else None
    
        for block in wiki_blocks:
            content = block.get("content", "").lower()
            block_type = block.get("type", "")
        
            if block_type in ["heading2", "heading_2"]:
                if "tech stack" in content:
                    tech_stack_order = block.get("order", 0)
                elif "development setup" in content:
                    dev_setup_order = block.get("order", 0)
    
        if tech_stack_order is not None and dev_setup_order is not None and tool_versions_order is not None:
            if tech_stack_order < tool_versions_order < dev_setup_order:
                checks_passed.append("[C] Tool Versions section correctly positioned between Tech Stack and Development Setup")
            else:
                # Don't fail on order, just note it
                checks_passed.append("[C] Tool Versions section present (order verification skipped)")
        else:
            checks_passed.append("[C] Block structure validation passed")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task 23: Meeting Notes Archive Summary
# =============================================================================
def _validate_meeting_notes_archive_summary(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Meeting Notes Archive Summary with aggregated meeting data and statistics."""
    errors: list[str] = []

    checks_passed = []
    
    # Check for Meeting Notes parent page
    try:
        meeting_notes = _find_page_by_title(final_state_backend, "Meeting Notes")
        if not meeting_notes:
            errors.append("[X] Meeting Notes page not found")
        else:
            checks_passed.append("[C] Meeting Notes page found")
    
        meeting_notes_id = meeting_notes.get("_id")
    
        # Get child pages under Meeting Notes (excluding the archive summary itself)
        meeting_children = _get_child_pages(final_state_backend, meeting_notes_id)
        meeting_pages = [p for p in meeting_children if "archive summary" not in p.get("title", "").lower()]
    
        if len(meeting_pages) < 2:
            errors.append(f"[X] Expected at least 2 meeting pages under Meeting Notes, found {len(meeting_pages)}")
        else:
            checks_passed.append(f"[C] Found {len(meeting_pages)} meeting pages under Meeting Notes")
    
        # Check for Meeting Notes Archive Summary page as child of Meeting Notes
        archive_summary = _find_page_by_title(final_state_backend, "Meeting Notes Archive Summary")
        if not archive_summary:
            errors.append("[X] Meeting Notes Archive Summary page not found")
        else:
            checks_passed.append("[C] Meeting Notes Archive Summary page found")
    
        # Verify it's a child of Meeting Notes
        if archive_summary.get("parentId") != meeting_notes_id:
            errors.append("[X] Meeting Notes Archive Summary is not a child of Meeting Notes")
        else:
            checks_passed.append("[C] Meeting Notes Archive Summary created under Meeting Notes")
    
        archive_summary_id = archive_summary.get("_id")
        summary_blocks = _get_blocks_for_page(final_state_backend, archive_summary_id)
    
        # 1. Check for heading_1 '📚 Meeting Notes Archive Summary'
        heading1_blocks = [
            b for b in summary_blocks 
            if b.get("type") in ["heading1", "heading_1"]
        ]
    
        found_main_heading = False
        for h in heading1_blocks:
            content = h.get("content", "")
            if "📚" in content and "meeting notes archive summary" in content.lower():
                found_main_heading = True
                break
    
        if not found_main_heading:
            errors.append("[X] Missing heading_1 '📚 Meeting Notes Archive Summary'")
        else:
            checks_passed.append("[C] Main heading '📚 Meeting Notes Archive Summary' present")
    
        # 2. Check for toggle block with '📅 Meeting Index (Click to expand)'
        toggle_blocks = [
            b for b in summary_blocks 
            if b.get("type") == "toggle"
        ]
    
        found_toggle = False
        for toggle in toggle_blocks:
            content = toggle.get("content", "")
            if "📅" in content and "meeting index" in content.lower():
                found_toggle = True
                break
    
        if not found_toggle:
            errors.append("[X] Missing toggle block '📅 Meeting Index (Click to expand)'")
        else:
            checks_passed.append("[C] Toggle block with Meeting Index present")
    
        # 3. Check for bulleted list inside toggle (meeting titles with icons)
        # Since toggle children may be separate blocks, check for bulleted list items
        bulleted_blocks = [
            b for b in summary_blocks 
            if b.get("type") in ["bulletedList", "bulleted_list", "bulleted_list_item", "bulleted"]
        ]
    
        # Verify each meeting page title appears in bulleted list
        meeting_titles_in_list = 0
        for meeting_page in meeting_pages:
            meeting_title = meeting_page.get("title", "").lower()
            meeting_icon = meeting_page.get("icon", "")
            for bullet in bulleted_blocks:
                bullet_content = bullet.get("content", "").lower()
                if meeting_title in bullet_content or any(word in bullet_content for word in meeting_title.split()):
                    meeting_titles_in_list += 1
                    break
    
        if meeting_titles_in_list < len(meeting_pages):
            errors.append(f"[X] Expected {len(meeting_pages)} meeting titles in bulleted list, found {meeting_titles_in_list}")
        else:
            checks_passed.append(f"[C] All {len(meeting_pages)} meeting titles listed with icons")
    
        # 4. Check for heading_2 '📊 Meeting Statistics'
        heading2_blocks = [
            b for b in summary_blocks 
            if b.get("type") in ["heading2", "heading_2"]
        ]
    
        found_stats_heading = False
        for h in heading2_blocks:
            content = h.get("content", "")
            if "📊" in content and "meeting statistics" in content.lower():
                found_stats_heading = True
                break
    
        if not found_stats_heading:
            errors.append("[X] Missing heading_2 '📊 Meeting Statistics'")
        else:
            checks_passed.append("[C] Meeting Statistics heading_2 present")
    
        # 5. Check for callout with gray_background and no icon
        callout_blocks = [
            b for b in summary_blocks 
            if b.get("type") == "callout"
        ]
    
        found_gray_callout = False
        for callout in callout_blocks:
            bg_color = callout.get("backgroundColor", "")
            properties = callout.get("properties", {})
            prop_bg = properties.get("backgroundColor", "")
            icon = callout.get("icon", "") or properties.get("icon", "")
        
            # Check for gray background
            is_gray = any("gray" in c.lower() for c in [bg_color, prop_bg] if c)
        
            # Check for no icon (icon should be empty/null/none)
            no_icon = not icon or icon.strip() == ""
        
            if is_gray:
                found_gray_callout = True
                if no_icon:
                    checks_passed.append("[C] Gray background callout with no icon present")
                else:
                    checks_passed.append("[C] Gray background callout present (icon optional)")
                break
    
        if not found_gray_callout:
            errors.append("[X] Missing callout with gray_background")
        else:
            checks_passed.append("[C] has callout with gray_background")
    
        # 6. Check for statistics paragraph blocks in callout
        paragraph_blocks = [
            b for b in summary_blocks 
            if b.get("type") in ["paragraph", "text"]
        ]
    
        # Calculate expected statistics
        total_meetings = len(meeting_pages)
        meetings_with_actions = 0
        total_blocks = 0
    
        for meeting_page in meeting_pages:
            page_id = meeting_page.get("_id")
            page_blocks = _get_blocks_for_page(final_state_backend, page_id)
            total_blocks += len(page_blocks)
        
            # Check for todo items
            has_todos = any(
                b.get("type") in ["todo", "to_do", "checkbox"]
                for b in page_blocks
            )
            if has_todos:
                meetings_with_actions += 1
    
        avg_blocks = total_blocks / total_meetings if total_meetings > 0 else 0
    
        # Check statistics content
        all_text_content = " ".join([b.get("content", "").lower() for b in paragraph_blocks])
    
        found_total = "total meetings documented" in all_text_content and str(total_meetings) in all_text_content
        found_actions = "meetings with action items" in all_text_content
        found_avg = "average blocks per meeting" in all_text_content
    
        if not found_total:
            errors.append(f"[X] Missing 'Total Meetings Documented: {total_meetings}' in statistics")
        else:
            checks_passed.append(f"[C] has 'Total Meetings Documented: {total_meetings}' in statistics")
        if not found_actions:
            errors.append("[X] Missing 'Meetings with Action Items' in statistics")
        else:
            checks_passed.append("[C] has 'Meetings with Action Items' in statistics")
        if not found_avg:
            errors.append("[X] Missing 'Average Blocks per Meeting' in statistics")
        else:
            checks_passed.append("[C] has 'Average Blocks per Meeting' in statistics")
    
        checks_passed.append(f"[C] Statistics present: Total={total_meetings}, Actions={meetings_with_actions}, Avg blocks calculated")
    
        # 7. Check for heading_3 for each meeting page with icon and title
        heading3_blocks = [
            b for b in summary_blocks 
            if b.get("type") in ["heading3", "heading_3"]
        ]
    
        meeting_headings_found = 0
        for meeting_page in meeting_pages:
            meeting_title = meeting_page.get("title", "").lower()
            meeting_icon = meeting_page.get("icon", "")
        
            for h in heading3_blocks:
                h_content = h.get("content", "")
                # Check if heading contains icon and title
                if meeting_icon in h_content and any(word in h_content.lower() for word in meeting_title.split()[:2]):
                    meeting_headings_found += 1
                    break
    
        if meeting_headings_found < len(meeting_pages):
            errors.append(f"[X] Expected {len(meeting_pages)} heading_3 for each meeting, found {meeting_headings_found}")
        else:
            checks_passed.append(f"[C] All {len(meeting_pages)} meeting heading_3 blocks with icons present")
    
        # 8. Check for quote blocks with meeting date info
        quote_blocks = [
            b for b in summary_blocks 
            if b.get("type") == "quote"
        ]
    
        if len(quote_blocks) < len(meeting_pages):
            errors.append(f"[X] Expected {len(meeting_pages)} quote blocks for meeting dates, found {len(quote_blocks)}")
        else:
            checks_passed.append(f"[C] Expected {len(meeting_pages)} quote blocks for meeting dates, found {len(quote_blocks)}")
    
        # Check quote content for date references
        date_quotes_found = 0
        for quote in quote_blocks:
            content = quote.get("content", "").lower()
            if "meeting date" in content or "date" in content:
                date_quotes_found += 1
    
        if date_quotes_found < len(meeting_pages):
            errors.append(f"[X] Expected quote blocks with 'Meeting date' info, found {date_quotes_found}")
        else:
            checks_passed.append(f"[C] Quote blocks with meeting dates present")
    
        # 9. Check for content blocks and todo count info in paragraphs
        content_info_found = 0
        for meeting_page in meeting_pages:
            page_id = meeting_page.get("_id")
            page_blocks = _get_blocks_for_page(final_state_backend, page_id)
            block_count = len(page_blocks)
        
            todo_count = sum(
                1 for b in page_blocks 
                if b.get("type") in ["todo", "to_do", "checkbox"]
            )
        
            # Look for content blocks count info
            for p in paragraph_blocks:
                p_content = p.get("content", "").lower()
                if "content blocks" in p_content and "todo items" in p_content:
                    content_info_found += 1
                    break
    
        if content_info_found < len(meeting_pages):
            # Be more lenient - just check that some verification info exists
            verification_found = any(
                "content blocks" in p.get("content", "").lower() or "todo" in p.get("content", "").lower()
                for p in paragraph_blocks
            )
            if not verification_found:
                errors.append("[X] Missing content blocks and todo count verification info")
            else:
                checks_passed.append("[C] has content blocks and todo count verification info")
    
        checks_passed.append("[C] Content blocks and todo count verification info present")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task 23: Company Handbook Reorganization
# =============================================================================
def _validate_company_handbook_reorganization(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Company Handbook reorganization with swapped sections, new Office Locations, and bookmark."""
    errors: list[str] = []

    checks_passed = []
    
    # Find the Company Handbook page
    try:
        handbook = _find_page_by_title(final_state_backend, "Company Handbook")
        if not handbook:
            errors.append("[X] Company Handbook page not found")
        else:
            checks_passed.append("[C] Company Handbook page found")
    
        handbook_id = handbook.get("_id")
        handbook_blocks = _get_blocks_for_page(final_state_backend, handbook_id)
    
        # Sort blocks by order to verify proper sequencing
        sorted_blocks = sorted(handbook_blocks, key=lambda b: b.get("order", 0))
    
        # Create a mapping of content types and positions for easier validation
        block_sequence = []
        for b in sorted_blocks:
            block_type = b.get("type", "")
            content = b.get("content", "")
            order = b.get("order", 0)
            properties = b.get("properties", {})
            block_sequence.append({
                "type": block_type,
                "content": content,
                "order": order,
                "properties": properties,
                "_id": b.get("_id", ""),
                "url": properties.get("url", ""),
                "caption": properties.get("caption", ""),
                "icon": properties.get("icon", ""),
                "backgroundColor": properties.get("backgroundColor", ""),
            })
    
        # Find indices of key sections
        benefits_heading_idx = None
        our_values_heading_idx = None
        work_policies_heading_idx = None
        office_locations_heading_idx = None
        time_off_heading_idx = None
    
        for i, block in enumerate(block_sequence):
            content_lower = block["content"].lower()
            block_type = block["type"]
        
            if block_type in ["heading2", "heading_2"]:
                if "benefits" in content_lower:
                    benefits_heading_idx = i
                elif "our values" in content_lower:
                    our_values_heading_idx = i
                elif "work policies" in content_lower:
                    work_policies_heading_idx = i
                elif "office locations" in content_lower:
                    office_locations_heading_idx = i
    
        # Check 1: Benefits section appears before Work Policies (was swapped with Our Values)
        if benefits_heading_idx is None:
            errors.append("[X] Benefits heading2 not found in Company Handbook")
        else:
            checks_passed.append("[C] Benefits heading2 found in Company Handbook")
    
        if our_values_heading_idx is None:
            errors.append("[X] Our Values heading2 not found in Company Handbook")
        else:
            checks_passed.append("[C] Our Values heading2 found in Company Handbook")
    
        if work_policies_heading_idx is None:
            errors.append("[X] Work Policies heading2 not found in Company Handbook")
        else:
            checks_passed.append("[C] Work Policies heading2 found in Company Handbook")
    
        # Verify Benefits comes before Work Policies (and before where Our Values originally was)
        if benefits_heading_idx >= work_policies_heading_idx:
            errors.append(f"[X] Benefits section (position {benefits_heading_idx}) should appear before Work Policies (position {work_policies_heading_idx})")
        else:
            checks_passed.append("[C] Benefits section now appears before Work Policies (swapped position)")
    
        # Check 2: Our Values appears after Work Policies (at the end where Benefits originally was)
        if our_values_heading_idx <= work_policies_heading_idx:
            errors.append(f"[X] Our Values section (position {our_values_heading_idx}) should appear after Work Policies (position {work_policies_heading_idx})")
        else:
            checks_passed.append("[C] Our Values section now appears after Work Policies (swapped position)")
    
        # Verify section contents are intact
        # Check Benefits section has numbered list items after it
        benefits_numbered_count = 0
        for i in range(benefits_heading_idx + 1, len(block_sequence)):
            block = block_sequence[i]
            if block["type"] in ["heading2", "heading_2"]:
                break  # Hit next section
            if block["type"] in ["numberedList", "numbered_list", "numbered_list_item", "numbered"]:
                benefits_numbered_count += 1
    
        if benefits_numbered_count < 4:
            errors.append(f"[X] Benefits section should have 4 numbered list items, found {benefits_numbered_count}")
        else:
            checks_passed.append("[C] Benefits section contains all 4 numbered list items")
    
        # Check Our Values section has bulleted list items after it
        our_values_bulleted_count = 0
        for i in range(our_values_heading_idx + 1, len(block_sequence)):
            block = block_sequence[i]
            if block["type"] in ["heading2", "heading_2"]:
                break  # Hit next section
            if block["type"] in ["bulletedList", "bulleted_list", "bulleted_list_item", "bulleted"]:
                our_values_bulleted_count += 1
    
        if our_values_bulleted_count < 3:
            errors.append(f"[X] Our Values section should have 3 bulleted list items, found {our_values_bulleted_count}")
        else:
            checks_passed.append("[C] Our Values section contains all 3 bulleted list items")
    
        # Check 3: Office Locations section between Benefits and Work Policies with yellow callout
        if office_locations_heading_idx is None:
            errors.append("[X] Office Locations heading2 not found - should be inserted between Benefits and Work Policies")
        else:
            checks_passed.append("[C] Office Locations heading2 found - should be inserted between Benefits and Work Policies")
    
        # Verify Office Locations heading has correct emoji
        office_heading_content = block_sequence[office_locations_heading_idx]["content"]
        if "🏢" not in office_heading_content:
            errors.append(f"[X] Office Locations heading should include '🏢' emoji, found: '{office_heading_content}'")
        else:
            checks_passed.append(f"[C] Office Locations heading should include '🏢' emoji, found: '{office_heading_content}'")
    
        # Verify Office Locations is between Benefits and Work Policies
        if not (benefits_heading_idx < office_locations_heading_idx < work_policies_heading_idx):
            errors.append(f"[X] Office Locations (position {office_locations_heading_idx}) should be between Benefits (position {benefits_heading_idx}) and Work Policies (position {work_policies_heading_idx})")
        else:
            checks_passed.append("[C] Office Locations section correctly positioned between Benefits and Work Policies")
    
        # Check for callout block after Office Locations heading with yellow background and 📍 icon
        callout_found = False
        for i in range(office_locations_heading_idx + 1, work_policies_heading_idx):
            block = block_sequence[i]
            if block["type"] == "callout":
                # Check for yellow background
                bg_color = block.get("backgroundColor", "")
                if not bg_color:
                    bg_color = block.get("properties", {}).get("backgroundColor", "")
            
                has_yellow_bg = "yellow" in bg_color.lower() if bg_color else False
            
                # Check for 📍 icon
                icon = block.get("icon", "")
                if not icon:
                    icon = block.get("properties", {}).get("icon", "")
                has_pin_icon = "📍" in icon if icon else False
            
                # Check content
                content = block.get("content", "")
                has_correct_content = (
                    "san francisco" in content.lower() and 
                    "new york" in content.lower() and 
                    "london" in content.lower() and 
                    "remote" in content.lower()
                )
            
                if has_yellow_bg and has_pin_icon and has_correct_content:
                    callout_found = True
                    break
                elif has_yellow_bg or has_pin_icon:
                    # Partial match - provide feedback
                    if not has_yellow_bg:
                        errors.append(f"[X] Office Locations callout should have yellow_background, found: '{bg_color}'")
                    else:
                        checks_passed.append(f"[C] Office Locations callout should have yellow_background, found: '{bg_color}'")
                    if not has_pin_icon:
                        errors.append(f"[X] Office Locations callout should have '📍' icon, found: '{icon}'")
                    else:
                        checks_passed.append(f"[C] Office Locations callout should have '📍' icon, found: '{icon}'")
                    if not has_correct_content:
                        errors.append(f"[X] Office Locations callout should mention San Francisco, New York, London, and remote work")
                    else:
                        checks_passed.append(f"[C] Office Locations callout should mention San Francisco, New York, London, and remote work")
    
        if not callout_found:
            errors.append("[X] Office Locations callout with yellow_background and '📍' icon not found")
        else:
            checks_passed.append("[C] Office Locations callout with yellow background and 📍 icon present")
    
        # Check 4: Bookmark block after Time Off paragraph
        # Find Time Off heading3
        time_off_idx = None
        for i, block in enumerate(block_sequence):
            if block["type"] in ["heading3", "heading_3"] and "time off" in block["content"].lower():
                time_off_idx = i
                break
    
        if time_off_idx is None:
            errors.append("[X] Time Off heading3 not found")
        else:
            checks_passed.append("[C] Time Off heading3 found")
    
        # Find the paragraph after Time Off
        time_off_paragraph_idx = None
        for i in range(time_off_idx + 1, len(block_sequence)):
            block = block_sequence[i]
            if block["type"] in ["paragraph", "text"]:
                time_off_paragraph_idx = i
                break
            if block["type"] in ["heading2", "heading_2", "heading3", "heading_3"]:
                break  # Hit another heading before finding paragraph
    
        if time_off_paragraph_idx is None:
            errors.append("[X] Time Off paragraph not found after heading")
        else:
            checks_passed.append("[C] Time Off paragraph found after heading")
    
        # Find bookmark block after the Time Off paragraph
        bookmark_found = False
        bookmark_url_correct = False
        bookmark_caption_correct = False
    
        for i in range(time_off_paragraph_idx + 1, len(block_sequence)):
            block = block_sequence[i]
            if block["type"] in ["heading2", "heading_2", "heading3", "heading_3"]:
                break  # Hit next section
            if block["type"] == "bookmark":
                bookmark_found = True
            
                # Check URL
                url = block.get("url", "") or block.get("properties", {}).get("url", "")
                if url == "https://company.notion.site/pto-policy":
                    bookmark_url_correct = True
            
                # Check caption
                caption = block.get("caption", "") or block.get("properties", {}).get("caption", "")
                if caption == "View detailed PTO policy":
                    bookmark_caption_correct = True
            
                break
    
        if not bookmark_found:
            errors.append("[X] Bookmark block not found after Time Off paragraph")
        else:
            checks_passed.append("[C] Bookmark block found after Time Off paragraph")
    
        if not bookmark_url_correct:
            errors.append(f"[X] Bookmark URL should be 'https://company.notion.site/pto-policy'")
        else:
            checks_passed.append(f"[C] Bookmark URL should be 'https://company.notion.site/pto-policy'")
    
        if not bookmark_caption_correct:
            errors.append(f"[X] Bookmark caption should be 'View detailed PTO policy'")
        else:
            checks_passed.append(f"[C] Bookmark caption should be 'View detailed PTO policy'")
    
        checks_passed.append("[C] Bookmark block added after Time Off paragraph with correct URL and caption")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task 24: Bug Tracking Summary Report
# =============================================================================
def _validate_bug_tracking_summary_report(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Bug Tracking Summary Report page with statistics callout and toggle block."""
    errors: list[str] = []

    checks_passed = []
    
    # Find Bug Tracker page (parent)
    try:
        bug_tracker = _find_page_by_title(final_state_backend, "Bug Tracker")
        if not bug_tracker:
            errors.append("[X] Bug Tracker page not found")
        else:
            checks_passed.append("[C] Bug Tracker page found")
    
        bug_tracker_id = bug_tracker.get("_id")
    
        # Check for the new summary report page as a child of Bug Tracker
        summary_report = _find_child_by_title_with_id(final_state_backend, bug_tracker_id, "Bug Tracking Summary Report")
    
        if summary_report and "📊" not in summary_report.get("title", ""):
            errors.append("[X] Bug Tracking Summary Report page should have '📊' emoji in title")
        else:
            checks_passed.append("[C] Bug Tracking Summary Report page should have '📊' emoji in title")
    
        if not summary_report:
            errors.append("[X] Bug Tracking Summary Report page not found as child of Bug Tracker")
        else:
            checks_passed.append("[C] Bug Tracking Summary Report page found as child of Bug Tracker")
    
        checks_passed.append("[C] Summary Report page created as child of Bug Tracker with correct title and emoji")
    
        report_id = summary_report.get("_id")
        report_blocks = _get_blocks_for_page(final_state_backend, report_id)
    
        # Sort blocks by order
        sorted_blocks = sorted(report_blocks, key=lambda b: b.get("order", 0))
    
        # Check for heading_1 '🐛 Bug Status Overview'
        has_overview_heading = any(
            b.get("type") in ["heading1", "heading_1"] and 
            "bug status overview" in b.get("content", "").lower() and 
            "🐛" in b.get("content", "")
            for b in sorted_blocks
        )
        if not has_overview_heading:
            errors.append("[X] Missing heading_1 '🐛 Bug Status Overview'")
        else:
            checks_passed.append("[C] Heading_1 '🐛 Bug Status Overview' present")
    
        # Check for heading_2 with today's date (flexible format)
        has_statistics_heading = any(
            b.get("type") in ["heading2", "heading_2"] and 
            "statistics" in b.get("content", "").lower() and 
            "📈" in b.get("content", "")
            for b in sorted_blocks
        )
        if not has_statistics_heading:
            errors.append("[X] Missing heading_2 '📈 Statistics as of [date]'")
        else:
            checks_passed.append("[C] Heading_2 with Statistics and date present")
    
        # Check for callout with blue_background and 📊 icon
        callout_found = False
        callout_has_metrics_content = False
    
        for block in sorted_blocks:
            if block.get("type") == "callout":
                properties = block.get("properties", {})
                bg_color = properties.get("backgroundColor", block.get("backgroundColor", ""))
                icon = properties.get("icon", block.get("icon", ""))
                content = block.get("content", "")
            
                has_blue_bg = "blue" in bg_color.lower() if bg_color else False
                has_chart_icon = "📊" in icon if icon else False
            
                if has_blue_bg and has_chart_icon:
                    callout_found = True
                    # Check for 'Bug Resolution Metrics' with bold
                    if "bug resolution metrics" in content.lower():
                        callout_has_metrics_content = True
                    break
    
        if not callout_found:
            errors.append("[X] Callout with blue_background and '📊' icon not found")
        else:
            checks_passed.append("[C] Callout with blue_background and '📊' icon present")
    
        if not callout_has_metrics_content:
            # Check if there's a paragraph with Bug Resolution Metrics near the callout
            metrics_found = any(
                "bug resolution metrics" in b.get("content", "").lower()
                for b in sorted_blocks
            )
            if not metrics_found:
                errors.append("[X] Missing 'Bug Resolution Metrics' text in callout content")
            else:
                checks_passed.append("[C] 'Bug Resolution Metrics' content present")
    
        # Check for bulleted list items with priority statistics
        # Expected: Critical Bugs, Medium Priority, Low Priority with resolved counts
        bulleted_items = [
            b for b in sorted_blocks 
            if b.get("type") in ["bulletedList", "bulleted_list", "bulleted_list_item", "bulleted"]
        ]
    
        critical_found = False
        medium_found = False
        low_found = False
    
        for item in bulleted_items:
            content = item.get("content", "").lower()
            if "critical" in content and "resolved" in content:
                # Verify format includes numbers and percentage
                if any(char.isdigit() for char in content) and "%" in content:
                    critical_found = True
            if "medium" in content and "resolved" in content:
                if any(char.isdigit() for char in content) and "%" in content:
                    medium_found = True
            if "low" in content and "resolved" in content:
                if any(char.isdigit() for char in content) and "%" in content:
                    low_found = True
    
        if not critical_found:
            errors.append("[X] Missing bulleted list item for 'Critical Bugs - Resolved: [X] of [Y] ([Z]%)'")
        else:
            checks_passed.append("[C] has bulleted list item for 'Critical Bugs - Resolved: [X] of [Y] ([Z]%)'")
        if not medium_found:
            errors.append("[X] Missing bulleted list item for 'Medium Priority - Resolved: [X] of [Y] ([Z]%)'")
        else:
            checks_passed.append("[C] has bulleted list item for 'Medium Priority - Resolved: [X] of [Y] ([Z]%)'")
        if not low_found:
            errors.append("[X] Missing bulleted list item for 'Low Priority - Resolved: [X] of [Y] ([Z]%)'")
        else:
            checks_passed.append("[C] has bulleted list item for 'Low Priority - Resolved: [X] of [Y] ([Z]%)'")
    
        checks_passed.append("[C] All three priority level statistics present with counts and percentages")
    
        # Check for toggle block with '🔍 View Unresolved Issues'
        toggle_found = any(
            b.get("type") == "toggle" and 
            "view unresolved issues" in b.get("content", "").lower() and
            "🔍" in b.get("content", "")
            for b in sorted_blocks
        )
    
        if not toggle_found:
            errors.append("[X] Missing toggle block with '🔍 View Unresolved Issues'")
        else:
            checks_passed.append("[C] Toggle block '🔍 View Unresolved Issues' present")
    
        # Check that toggle contains numbered list items (the unresolved todos)
        # Note: toggle children may be stored differently depending on the implementation
        # We'll check for numbered list blocks in the page that might be toggle children
        numbered_items = [
            b for b in sorted_blocks 
            if b.get("type") in ["numberedList", "numbered_list", "numbered_list_item", "numbered"]
        ]
    
        # Should have at least 3 unresolved issues based on the Bug Tracker data:
        # 1. [Critical] Resolve data sync conflict in offline mode
        # 2. [Medium] Search results not updating in real-time
        # 3. [Low] Tooltip text cut off on small screens
        if len(numbered_items) < 3:
            errors.append(f"[X] Toggle should contain numbered list of at least 3 unresolved issues, found {len(numbered_items)}")
        else:
            checks_passed.append(f"[C] Toggle should contain numbered list of at least 3 unresolved issues, found {len(numbered_items)}")
    
        # Check that numbered items have priority prefixes
        has_priority_prefixes = False
        for item in numbered_items:
            content = item.get("content", "").lower()
            if "[critical]" in content or "[medium]" in content or "[low]" in content or \
               "critical:" in content or "medium:" in content or "low:" in content:
                has_priority_prefixes = True
                break
    
        if not has_priority_prefixes:
            errors.append("[X] Numbered list items should have priority level prefixes (e.g., [Critical], [Medium], [Low])")
        else:
            checks_passed.append("[C] Numbered list items should have priority level prefixes (e.g., [Critical], [Medium], [Low])")
    
        checks_passed.append("[C] Numbered list of unresolved issues with priority prefixes present")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_architecture_overview(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Architecture Overview page with statistics callout, section lists, and hierarchy toggle."""
    errors: list[str] = []

    checks_passed = []
    
    # Find Project Documentation page
    try:
        project_docs = _find_page_by_title(final_state_backend, "Project Documentation")
        if not project_docs:
            errors.append("[X] Project Documentation page not found")
        else:
            checks_passed.append("[C] Project Documentation page found")
    
        project_docs_id = project_docs.get("_id")
    
        # Find Architecture page as child of Project Documentation
        architecture = _find_child_by_title(final_state_backend, project_docs, "Architecture")
        if not architecture:
            errors.append("[X] Architecture page not found under Project Documentation")
        else:
            checks_passed.append("[C] Architecture page found under Project Documentation")
    
        architecture_id = architecture.get("_id")
        checks_passed.append("[C] Architecture page found under Project Documentation")
    
        # Check for Architecture Overview page as child of Architecture
        overview_page = _find_child_by_title(final_state_backend, architecture, "Architecture Overview")
        if not overview_page:
            errors.append("[X] Architecture Overview page not found as child of Architecture")
        else:
            checks_passed.append("[C] Architecture Overview page found as child of Architecture")
    
        # Check title has 🏗️ emoji
        overview_title = overview_page.get("title", "")
        if "🏗️" not in overview_title and "architecture overview" not in overview_title.lower():
            errors.append("[X] Architecture Overview page should have '🏗️' emoji and 'Architecture Overview' in title")
        else:
            checks_passed.append("[C] Architecture Overview page should have '🏗️' emoji and 'Architecture Overview' in title")
    
        checks_passed.append("[C] Architecture Overview page created as child of Architecture with correct title")
    
        overview_id = overview_page.get("_id")
        overview_blocks = _get_blocks_for_page(final_state_backend, overview_id)
    
        # Sort blocks by order
        sorted_blocks = sorted(overview_blocks, key=lambda b: b.get("order", 0))
    
        # Check for heading_1 '🏗️ Architecture Overview'
        has_main_heading = any(
            b.get("type") in ["heading1", "heading_1"] and 
            "architecture overview" in b.get("content", "").lower() and 
            "🏗️" in b.get("content", "")
            for b in sorted_blocks
        )
        if not has_main_heading:
            errors.append("[X] Missing heading_1 '🏗️ Architecture Overview'")
        else:
            checks_passed.append("[C] Heading_1 '🏗️ Architecture Overview' present")
    
        # Build hierarchy of Architecture page and its children
        architecture_hierarchy = _build_page_hierarchy(final_state_backend, architecture_id)
        all_architecture_pages = _get_all_pages_in_hierarchy(architecture_hierarchy)
        # Exclude the Architecture page itself from counts
        child_architecture_pages = [p for p in all_architecture_pages if p.get("_id") != architecture_id]
    
        # Count Frontend and Backend pages
        frontend_pages = [p for p in child_architecture_pages if "frontend" in p.get("title", "").lower()]
        backend_pages = [p for p in child_architecture_pages if "backend" in p.get("title", "").lower()]
    
        total_count = len(child_architecture_pages)
        frontend_count = len(frontend_pages)
        backend_count = len(backend_pages)
    
        # Check for blue callout with Document Statistics
        callout_found = False
        callout_has_stats = False
        callout_has_bullets = False
    
        for block in sorted_blocks:
            if block.get("type") == "callout":
                properties = block.get("properties", {})
                bg_color = properties.get("backgroundColor", block.get("backgroundColor", ""))
                icon = properties.get("icon", block.get("icon", ""))
                content = block.get("content", "")
            
                has_blue_bg = "blue" in bg_color.lower() if bg_color else False
                has_no_icon = not icon or icon == "" or icon is None
            
                if has_blue_bg and has_no_icon:
                    callout_found = True
                    # Check for heading_3 'Document Statistics'
                    if "document statistics" in content.lower():
                        callout_has_stats = True
                    break
    
        if not callout_found:
            errors.append("[X] Callout with blue_background and no icon not found")
        else:
            checks_passed.append("[C] Blue callout with no icon present")
    
        if not callout_has_stats:
            # Check if heading_3 exists near the callout
            has_stats_heading = any(
                b.get("type") in ["heading3", "heading_3"] and 
                "document statistics" in b.get("content", "").lower()
                for b in sorted_blocks
            )
            if not has_stats_heading:
                errors.append("[X] Missing heading_3 'Document Statistics' in callout")
            else:
                checks_passed.append("[C] has heading_3 'Document Statistics' in callout")
    
        checks_passed.append("[C] Heading_3 'Document Statistics' present")
    
        # Check for bulleted list items with statistics
        bulleted_items = [
            b for b in sorted_blocks 
            if b.get("type") in ["bulletedList", "bulleted_list", "bulleted_list_item", "bulleted"]
        ]
    
        total_found = False
        frontend_found = False
        backend_found = False
        total_count_match = False
        frontend_count_match = False
        backend_count_match = False
    
        for item in bulleted_items:
            content = item.get("content", "")
            content_lower = content.lower()
        
            if "total architecture pages" in content_lower:
                total_found = True
                # Extract number from content
                numbers = re.findall(r'\d+', content)
                if numbers:
                    reported_total = int(numbers[0])
                    if reported_total == total_count:
                        total_count_match = True
        
            if "frontend pages" in content_lower:
                frontend_found = True
                numbers = re.findall(r'\d+', content)
                if numbers:
                    reported_frontend = int(numbers[0])
                    if reported_frontend == frontend_count:
                        frontend_count_match = True
        
            if "backend pages" in content_lower:
                backend_found = True
                numbers = re.findall(r'\d+', content)
                if numbers:
                    reported_backend = int(numbers[0])
                    if reported_backend == backend_count:
                        backend_count_match = True
    
        if not total_found:
            errors.append("[X] Missing bulleted list item for 'Total architecture pages: [X]'")
        else:
            checks_passed.append("[C] has bulleted list item for 'Total architecture pages: [X]'")
        if not frontend_found:
            errors.append("[X] Missing bulleted list item for 'Frontend pages: [Y]'")
        else:
            checks_passed.append("[C] has bulleted list item for 'Frontend pages: [Y]'")
        if not backend_found:
            errors.append("[X] Missing bulleted list item for 'Backend pages: [Z]'")
        else:
            checks_passed.append("[C] has bulleted list item for 'Backend pages: [Z]'")
    
        if not total_count_match:
            errors.append(f"[X] Total architecture pages count incorrect: expected {total_count}")
        else:
            checks_passed.append(f"[C] Total architecture pages count incorrect: expected {total_count}")
        if not frontend_count_match:
            errors.append(f"[X] Frontend pages count incorrect: expected {frontend_count}")
        else:
            checks_passed.append(f"[C] Frontend pages count incorrect: expected {frontend_count}")
        if not backend_count_match:
            errors.append(f"[X] Backend pages count incorrect: expected {backend_count}")
        else:
            checks_passed.append(f"[C] Backend pages count incorrect: expected {backend_count}")
    
        checks_passed.append("[C] All three statistics bullet points present with accurate counts")
    
        # Check for heading_2 sections with emojis
        # Frontend section: 🎨 Frontend
        frontend_heading_found = False
        backend_heading_found = False
    
        for block in sorted_blocks:
            if block.get("type") in ["heading2", "heading_2"]:
                content = block.get("content", "")
                content_lower = content.lower()
            
                if "🎨" in content and "frontend" in content_lower:
                    frontend_heading_found = True
                if "⚙️" in content and "backend" in content_lower:
                    backend_heading_found = True
    
        if not frontend_heading_found:
            errors.append("[X] Missing heading_2 with '🎨 Frontend'")
        else:
            checks_passed.append("[C] Heading_2 '🎨 Frontend' present")
    
        if not backend_heading_found:
            errors.append("[X] Missing heading_2 with '⚙️ Backend'")
        else:
            checks_passed.append("[C] Heading_2 '⚙️ Backend' present")
    
        # Check for numbered lists under each section
        numbered_items = [
            b for b in sorted_blocks 
            if b.get("type") in ["numberedList", "numbered_list", "numbered_list_item", "numbered"]
        ]
    
        if len(numbered_items) < total_count:
            errors.append(f"[X] Expected at least {total_count} numbered list items for all child pages, found {len(numbered_items)}")
        else:
            checks_passed.append(f"[C] Expected at least {total_count} numbered list items for all child pages, found {len(numbered_items)}")
    
        # Check that numbered items contain page icons and titles
        # Verify that page titles appear in the numbered list
        all_numbered_content = " ".join([item.get("content", "") for item in numbered_items]).lower()
    
        # Check that frontend pages are mentioned in numbered lists
        frontend_pages_found = 0
        for frontend_page in frontend_pages:
            page_title = frontend_page.get("title", "").lower()
            # Check if the page title (or a significant part of it) appears in numbered items
            if page_title and len(page_title) > 3:
                # Extract key words from title (remove common words like "architecture")
                key_words = [w for w in page_title.split() if w not in ["architecture", "frontend", "backend"]]
                if key_words:
                    for word in key_words:
                        if word in all_numbered_content:
                            frontend_pages_found += 1
                            break
    
        # Check that backend pages are mentioned in numbered lists
        backend_pages_found = 0
        for backend_page in backend_pages:
            page_title = backend_page.get("title", "").lower()
            if page_title and len(page_title) > 3:
                key_words = [w for w in page_title.split() if w not in ["architecture", "frontend", "backend"]]
                if key_words:
                    for word in key_words:
                        if word in all_numbered_content:
                            backend_pages_found += 1
                            break
    
        # Verify that numbered items have icon format (emoji or special character at start)
        has_icon_format = False
        for item in numbered_items[:min(5, len(numbered_items))]:  # Check first few items
            content = item.get("content", "")
            if content and len(content.strip()) > 3:
                # Check if content starts with an emoji or special character (icon)
                first_char = content.strip()[0]
                if ord(first_char) > 127 or first_char in ["[", "•", "-"]:  # Emoji or special char
                    has_icon_format = True
                    break
    
        if not has_icon_format and numbered_items:
            errors.append("[X] Numbered list items should have format '[Page Icon] [Page Title]' with icon prefix")
        else:
            checks_passed.append("[C] Numbered list items should have format '[Page Icon] [Page Title]' with icon prefix")
    
        # We expect at least some pages to be found (flexible matching)
        if frontend_count > 0 and frontend_pages_found == 0:
            errors.append(f"[X] Frontend pages not found in numbered list (expected {frontend_count} pages)")
        else:
            checks_passed.append(f"[C] Frontend pages found in numbered list (expected {frontend_count} pages)")
        if backend_count > 0 and backend_pages_found == 0:
            errors.append(f"[X] Backend pages not found in numbered list (expected {backend_count} pages)")
        else:
            checks_passed.append(f"[C] Backend pages found in numbered list (expected {backend_count} pages)")
    
        checks_passed.append(f"[C] Numbered lists present with page icons and titles ({frontend_pages_found} frontend, {backend_pages_found} backend pages found)")
    
        # Check for toggle block '📊 Architecture Hierarchy'
        toggle_found = any(
            b.get("type") == "toggle" and 
            "architecture hierarchy" in b.get("content", "").lower() and
            "📊" in b.get("content", "")
            for b in sorted_blocks
        )
    
        if not toggle_found:
            errors.append("[X] Missing toggle block with '📊 Architecture Hierarchy'")
        else:
            checks_passed.append("[C] Toggle block '📊 Architecture Hierarchy' present")
    
        # Check that toggle contains nested bulleted lists (hierarchy structure)
        # Note: Toggle children might be stored differently, but we check for bulleted lists
        # that could represent the hierarchy
        nested_bullets = [
            b for b in sorted_blocks 
            if b.get("type") in ["bulletedList", "bulleted_list", "bulleted_list_item", "bulleted"]
        ]
    
        # We expect at least some nested structure (multiple levels of bullets)
        # This is a simplified check - in a real implementation, we'd check parent-child relationships
        if len(nested_bullets) < total_count:
            errors.append(f"[X] Toggle should contain nested bulleted lists showing hierarchy for {total_count} pages, found {len(nested_bullets)} bullet items")
        else:
            checks_passed.append(f"[C] Toggle should contain nested bulleted lists showing hierarchy for {total_count} pages, found {len(nested_bullets)} bullet items")
    
        checks_passed.append("[C] Toggle contains nested bulleted lists showing page hierarchy")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Team Productivity Dashboard
# =============================================================================
def _validate_team_productivity_dashboard(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Team Productivity Dashboard page with task statistics from Sprint Planning and Weekly Standup Template."""
    errors: list[str] = []

    checks_passed = []
    
    # Find Meeting Notes page (parent)
    try:
        meeting_notes = _find_page_by_title(final_state_backend, "Meeting Notes")
        if not meeting_notes:
            errors.append("[X] Meeting Notes page not found")
        else:
            checks_passed.append("[C] Meeting Notes page found")
    
        meeting_notes_id = meeting_notes.get("_id")
    
        # Check for the new Team Productivity Dashboard page as a child of Meeting Notes
        child_pages = _get_child_pages(final_state_backend, meeting_notes_id)
        dashboard_page = None
        for page in child_pages:
            title = page.get("title", "")
            if "team productivity dashboard" in title.lower():
                dashboard_page = page
                break
    
        if not dashboard_page:
            errors.append("[X] Team Productivity Dashboard page not found under Meeting Notes")
        else:
            checks_passed.append("[C] Team Productivity Dashboard page found under Meeting Notes")
    
        checks_passed.append("[C] Team Productivity Dashboard page created under Meeting Notes")
    
        dashboard_id = dashboard_page.get("_id")
        dashboard_blocks = _get_blocks_for_page(final_state_backend, dashboard_id)
    
        # Sort blocks by order
        sorted_blocks = sorted(dashboard_blocks, key=lambda b: b.get("order", 0))
    
        # Check for heading_1 '📊 Team Productivity Dashboard'
        has_main_heading = any(
            b.get("type") in ["heading1", "heading_1"] and 
            "team productivity dashboard" in b.get("content", "").lower() and 
            "📊" in b.get("content", "")
            for b in sorted_blocks
        )
        if not has_main_heading:
            errors.append("[X] Missing heading_1 '📊 Team Productivity Dashboard'")
        else:
            checks_passed.append("[C] Heading_1 '📊 Team Productivity Dashboard' present")
    
        # Check for heading_2 '⏱️ Sprint Velocity Metrics'
        has_velocity_heading = any(
            b.get("type") in ["heading2", "heading_2"] and 
            "sprint velocity metrics" in b.get("content", "").lower() and 
            "⏱️" in b.get("content", "")
            for b in sorted_blocks
        )
        if not has_velocity_heading:
            errors.append("[X] Missing heading_2 '⏱️ Sprint Velocity Metrics'")
        else:
            checks_passed.append("[C] Heading_2 '⏱️ Sprint Velocity Metrics' present")
    
        # Find Sprint Planning - Jan 15 and Weekly Standup Template pages to count todos
        sprint_planning = _find_page_by_title(final_state_backend, "Sprint Planning - Jan 15")
        weekly_standup = _find_page_by_title(final_state_backend, "Weekly Standup Template")
    
        if not sprint_planning:
            errors.append("[X] Sprint Planning - Jan 15 page not found (required for analysis)")
        else:
            checks_passed.append("[C] Sprint Planning - Jan 15 page found (required for analysis)")
        if not weekly_standup:
            errors.append("[X] Weekly Standup Template page not found (required for analysis)")
        else:
            checks_passed.append("[C] Weekly Standup Template page found (required for analysis)")
    
        # Count todos from both pages
        sprint_planning_id = sprint_planning.get("_id")
        weekly_standup_id = weekly_standup.get("_id")
    
        # Get todo blocks from both pages - using query-level filtering
        sprint_todos = _get_todo_blocks(final_state_backend, sprint_planning_id)
        standup_todos = _get_todo_blocks(final_state_backend, weekly_standup_id)
    
        all_todos = sprint_todos + standup_todos
        total_tasks = len(all_todos)
        completed_tasks = sum(1 for t in all_todos if t.get("properties", {}).get("checked", False))
        completion_rate = round((completed_tasks / total_tasks * 100) if total_tasks > 0 else 0)
    
        # Check for callout with yellow background showing task statistics
        callout_found = False
        callout_has_correct_stats = False
    
        for block in sorted_blocks:
            if block.get("type") == "callout":
                properties = block.get("properties", {})
                bg_color = properties.get("backgroundColor", block.get("backgroundColor", ""))
                content = block.get("content", "")
            
                has_yellow_bg = "yellow" in bg_color.lower() if bg_color else False
            
                if has_yellow_bg:
                    callout_found = True
                    # Check for total tasks count and completion rate
                    content_lower = content.lower()
                    has_total = "total tasks tracked" in content_lower
                    has_completion = "completion rate" in content_lower
                
                    # Extract numbers from content to verify accuracy
                    numbers = re.findall(r'\d+', content)
                
                    # Check if the total tasks count is accurate (allow some flexibility)
                    if has_total and has_completion and numbers:
                        reported_total = int(numbers[0]) if numbers else 0
                        # Allow flexibility in task count based on what the agent found
                        if reported_total >= 2:  # At least 2 tasks
                            callout_has_correct_stats = True
                    break
    
        if not callout_found:
            errors.append("[X] Callout with yellow_background not found")
        else:
            checks_passed.append("[C] Callout with yellow_background present")
    
        if not callout_has_correct_stats:
            errors.append("[X] Callout should show 'Total tasks tracked: [X], Completion rate: [Y]%'")
        else:
            checks_passed.append("[C] Callout shows task statistics (total tasks and completion rate)")
    
        # Check for heading_3 '👥 Individual Contributions'
        has_contributions_heading = any(
            b.get("type") in ["heading3", "heading_3"] and 
            "individual contributions" in b.get("content", "").lower() and 
            "👥" in b.get("content", "")
            for b in sorted_blocks
        )
        if not has_contributions_heading:
            errors.append("[X] Missing heading_3 '👥 Individual Contributions'")
        else:
            checks_passed.append("[C] Heading_3 '👥 Individual Contributions' present")
    
        # Check for paragraphs with bold names for Alice and Bob
        paragraphs = [b for b in sorted_blocks if b.get("type") in ["paragraph", "text"]]
    
        alice_found = False
        bob_found = False
    
        for para in paragraphs:
            content = para.get("content", "").lower()
            properties = para.get("properties", {})
        
            # Check for Alice with task count
            if "alice" in content and "task" in content:
                alice_found = True
        
            # Check for Bob with task count
            if "bob" in content and "task" in content:
                bob_found = True
    
        if not alice_found:
            errors.append("[X] Missing paragraph with bold text '**Alice**: [number] tasks assigned'")
        else:
            checks_passed.append("[C] has paragraph with bold text '**Alice**: [number] tasks assigned'")
        if not bob_found:
            errors.append("[X] Missing paragraph with bold text '**Bob**: [number] tasks assigned'")
        else:
            checks_passed.append("[C] has paragraph with bold text '**Bob**: [number] tasks assigned'")
    
        checks_passed.append("[C] Individual contribution paragraphs for Alice and Bob present with task counts")
    
        # Check for divider
        has_divider = any(
            b.get("type") == "divider"
            for b in sorted_blocks
        )
        if not has_divider:
            errors.append("[X] Missing divider before toggle block")
        else:
            checks_passed.append("[C] Divider present")
    
        # Check for toggle block '📈 Detailed Task Breakdown'
        toggle_found = any(
            b.get("type") == "toggle" and 
            "detailed task breakdown" in b.get("content", "").lower() and
            "📈" in b.get("content", "")
            for b in sorted_blocks
        )
    
        if not toggle_found:
            errors.append("[X] Missing toggle block with '📈 Detailed Task Breakdown'")
        else:
            checks_passed.append("[C] Toggle block '📈 Detailed Task Breakdown' present")
    
        # Check that toggle contains bulleted list items (completed task descriptions)
        # Note: toggle children may be stored differently depending on the implementation
        # We'll check for bulleted list blocks in the page
        bulleted_items = [
            b for b in sorted_blocks 
            if b.get("type") in ["bulletedList", "bulleted_list", "bulleted_list_item", "bulleted"]
        ]
    
        # Should have at least some completed tasks listed
        # From the data: 4 completed tasks total
        if len(bulleted_items) < 2:
            errors.append(f"[X] Toggle should contain bulleted list of completed task descriptions, found {len(bulleted_items)} bullet items")
        else:
            checks_passed.append(f"[C] Toggle should contain bulleted list of completed task descriptions, found {len(bulleted_items)} bullet items")
    
        # Check that bulleted items contain completed task content
        all_bullet_content = " ".join([item.get("content", "") for item in bulleted_items]).lower()
    
        # Verify at least some completed task descriptions are present
        # Known completed tasks: "wireframes", "drag-and-drop", "feature x", "pull requests"
        completed_task_keywords = ["wireframe", "drag", "feature", "pull request", "review", "completed"]
        keywords_found = sum(1 for kw in completed_task_keywords if kw in all_bullet_content)
    
        if keywords_found < 1:
            errors.append("[X] Bulleted list should contain completed task descriptions from both pages")
        else:
            checks_passed.append("[C] Bulleted list should contain completed task descriptions from both pages")
    
        checks_passed.append("[C] Bulleted list of completed task descriptions present in toggle")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Bug Tracker Conditional Formatting
# =============================================================================
def _validate_bug_tracker_conditional_formatting(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Bug Tracker page with conditional formatting, statistics, and triage callout."""
    errors: list[str] = []

    checks_passed = []
    
    # Find Bug Tracker page
    try:
        bug_tracker = _find_page_by_title(final_state_backend, "Bug Tracker")
        if not bug_tracker:
            errors.append("[X] Bug Tracker page not found")
        else:
            checks_passed.append("[C] Bug Tracker page found")
    
        bug_tracker_id = bug_tracker.get("_id")
        bug_tracker_blocks = _get_blocks_for_page(final_state_backend, bug_tracker_id)
    
        # Sort blocks by order
        sorted_blocks = sorted(bug_tracker_blocks, key=lambda b: b.get("order", 0))
    
        # Find all todo blocks and categorize them
        todo_blocks = []
        for i, block in enumerate(sorted_blocks):
            if block.get("type") in ["todo", "to_do", "checkbox"]:
                content = block.get("content", "")
                is_checked = block.get("properties", {}).get("checked", False)
                todo_blocks.append({
                    "block": block,
                    "index": i,
                    "content": content,
                    "checked": is_checked,
                    "needs_priority_callout": not is_checked and (
                        "critical" in content.lower() or "sync" in content.lower()
                    )
                })
    
        if not todo_blocks:
            errors.append("[X] No todo blocks found in Bug Tracker page")
        else:
            checks_passed.append("[C] todo blocks found in Bug Tracker page")
    
        # Calculate statistics
        total_todos = len(todo_blocks)
        checked_todos = sum(1 for t in todo_blocks if t["checked"])
        unchecked_todos = total_todos - checked_todos
        fix_rate = round((checked_todos / total_todos) * 100, 1) if total_todos > 0 else 0.0
    
        checks_passed.append(f"[C] Found {total_todos} todos: {checked_todos} fixed, {unchecked_todos} active")
    
        # Find todos that need priority callouts (unchecked with 'critical' or 'sync')
        priority_todos = [t for t in todo_blocks if t["needs_priority_callout"]]
    
        # Check 1: Red callouts before unchecked todos containing 'critical' or 'sync'
        if priority_todos:
            red_callout_count = 0
            for priority_todo in priority_todos:
                todo_idx = priority_todo["index"]
                todo_content = priority_todo["content"]
            
                # Look for a red callout immediately before this todo
                found_red_callout = False
            
                # Check the block immediately before the todo
                if todo_idx > 0:
                    prev_block = sorted_blocks[todo_idx - 1]
                    if prev_block.get("type") == "callout":
                        properties = prev_block.get("properties", {})
                        bg_color = properties.get("backgroundColor", prev_block.get("backgroundColor", ""))
                        icon = properties.get("icon", prev_block.get("icon", ""))
                        content = prev_block.get("content", "")
                    
                        has_red_bg = "red" in bg_color.lower() if bg_color else False
                        has_alert_icon = "🚨" in icon if icon else False
                        has_priority_text = "high priority" in content.lower() or "immediate attention" in content.lower()
                    
                        if has_red_bg and has_alert_icon and has_priority_text:
                            found_red_callout = True
                            red_callout_count += 1
            
                # Also check if any callout exists near the todo (within 2 blocks before)
                if not found_red_callout:
                    for check_idx in range(max(0, todo_idx - 2), todo_idx):
                        check_block = sorted_blocks[check_idx]
                        if check_block.get("type") == "callout":
                            properties = check_block.get("properties", {})
                            bg_color = properties.get("backgroundColor", check_block.get("backgroundColor", ""))
                            icon = properties.get("icon", check_block.get("icon", ""))
                            content = check_block.get("content", "")
                        
                            has_red_bg = "red" in bg_color.lower() if bg_color else False
                            has_alert_icon = "🚨" in icon if icon else False
                            has_priority_text = "high priority" in content.lower() or "immediate attention" in content.lower()
                        
                            if has_red_bg and has_alert_icon and has_priority_text:
                                found_red_callout = True
                                red_callout_count += 1
                                break
            
                if not found_red_callout:
                    keyword = "sync" if "sync" in todo_content.lower() else "critical"
                    errors.append(f"[X] Missing red callout (red_background, 🚨 icon, 'HIGH PRIORITY') before todo containing '{keyword}': '{todo_content[:50]}...'")
                else:
                    checks_passed.append(f"[C] has red callout (red_background, 🚨 icon, 'HIGH PRIORITY') before todo containing '{keyword}': '{todo_content[:50]}...'")
        
            checks_passed.append(f"[C] Red priority callouts found before {red_callout_count} high-priority unchecked todos")
        else:
            checks_passed.append("[C] No unchecked todos with 'critical' or 'sync' found (no red callouts needed)")
    
        # Check 2: Find In Progress and Low Priority headings and verify divider + statistics heading + paragraph
        # are positioned after In Progress section but before Low Priority heading
        in_progress_idx = None
        low_priority_idx = None
        for i, block in enumerate(sorted_blocks):
            if block.get("type") in ["heading2", "heading_2"]:
                content = block.get("content", "").lower()
                if "in progress" in content and in_progress_idx is None:
                    in_progress_idx = i
                elif ("low priority" in content or "low" in content) and low_priority_idx is None:
                    low_priority_idx = i
    
        # Find the last todo in the In Progress section (before Low Priority)
        last_in_progress_todo_idx = None
        if in_progress_idx is not None:
            end_idx = low_priority_idx if low_priority_idx is not None else len(sorted_blocks)
            for i in range(in_progress_idx + 1, end_idx):
                block = sorted_blocks[i]
                if block.get("type") in ["todo", "to_do", "checkbox"]:
                    last_in_progress_todo_idx = i
    
        # Look for statistics section - should be after In Progress todos but before Low Priority
        stats_heading_found = False
        stats_paragraph_found = False
        divider_found = False
        stats_heading_idx = None
    
        # Search for '📊 Bug Statistics' heading_3
        for i, block in enumerate(sorted_blocks):
            if block.get("type") in ["heading3", "heading_3"]:
                content = block.get("content", "")
                if "bug statistics" in content.lower() and "📊" in content:
                    stats_heading_found = True
                    stats_heading_idx = i
                
                    # Check for divider before this heading
                    for check_idx in range(max(0, i - 3), i):
                        if sorted_blocks[check_idx].get("type") == "divider":
                            divider_found = True
                            break
                
                    # Check for paragraph after this heading with stats
                    for check_idx in range(i + 1, min(len(sorted_blocks), i + 4)):
                        check_block = sorted_blocks[check_idx]
                        if check_block.get("type") in ["paragraph", "text"]:
                            content = check_block.get("content", "")
                            # Check for stats format: 'Active Bugs: [X] | Fixed: [Y] | Fix Rate: [Z]%'
                            if "active bugs" in content.lower() and "fixed" in content.lower() and "fix rate" in content.lower():
                                stats_paragraph_found = True
                            
                                # Verify the numbers are reasonable
                                numbers = re.findall(r'(\d+(?:\.\d+)?)', content)
                                if len(numbers) >= 3:
                                    # The paragraph should contain counts and percentage
                                    checks_passed.append(f"[C] Statistics paragraph found with values: {numbers}")
                                break
                    break
    
        if not divider_found:
            errors.append("[X] Missing divider before '📊 Bug Statistics' heading")
        else:
            checks_passed.append("[C] Divider found before Bug Statistics section")
    
        if not stats_heading_found:
            errors.append("[X] Missing heading_3 '📊 Bug Statistics'")
        else:
            checks_passed.append("[C] Heading_3 '📊 Bug Statistics' present")
    
        if not stats_paragraph_found:
            errors.append("[X] Missing paragraph with 'Active Bugs: [X] | Fixed: [Y] | Fix Rate: [Z]%'")
        else:
            checks_passed.append("[C] Statistics paragraph with correct format present")
    
        # Verify positioning: stats should be after In Progress section and before Low Priority
        if stats_heading_idx is not None:
            if last_in_progress_todo_idx is not None and stats_heading_idx <= last_in_progress_todo_idx:
                errors.append("[X] Bug Statistics section should be placed AFTER the last todo in the 'In Progress' section")
            else:
                checks_passed.append("[C] Bug Statistics section should be placed AFTER the last todo in the 'In Progress' section")
            if low_priority_idx is not None and stats_heading_idx >= low_priority_idx:
                errors.append("[X] Bug Statistics section should be placed BEFORE the 'Low Priority' heading")
            else:
                checks_passed.append("[C] Bug Statistics correctly positioned after In Progress section and before Low Priority")
    
        # Check 3: Blue callout with date at the end of page
        # Look for callout with blue background and 🔄 icon containing date
        blue_callout_found = False
        date_callout_correct = False
    
        # Search from the end of the page backwards
        for block in reversed(sorted_blocks):
            if block.get("type") == "callout":
                properties = block.get("properties", {})
                bg_color = properties.get("backgroundColor", block.get("backgroundColor", ""))
                icon = properties.get("icon", block.get("icon", ""))
                content = block.get("content", "")
            
                has_blue_bg = "blue" in bg_color.lower() if bg_color else False
                has_refresh_icon = "🔄" in icon if icon else False
            
                if has_blue_bg and has_refresh_icon:
                    blue_callout_found = True
                    # Check for date format: 'Last triaged: [date]'
                    if "last triaged" in content.lower():
                        # Check for date pattern (January X, 2025 or similar)
                        date_pattern = r'(january|february|march|april|may|june|july|august|september|october|november|december)\s+\d{1,2},?\s*\d{4}'
                        if re.search(date_pattern, content.lower()):
                            date_callout_correct = True
                        # Also accept other date formats
                        elif re.search(r'\d{1,2}[/-]\d{1,2}[/-]\d{2,4}', content):
                            date_callout_correct = True
                        elif re.search(r'\d{4}[/-]\d{1,2}[/-]\d{1,2}', content):
                            date_callout_correct = True
                    break
    
        if not blue_callout_found:
            errors.append("[X] Missing blue callout with '🔄' icon at end of page")
        else:
            checks_passed.append("[C] Blue callout with '🔄' icon found at end of page")
    
        if not date_callout_correct:
            errors.append("[X] Blue callout should contain 'Last triaged: [date]' with proper date format")
        else:
            checks_passed.append("[C] Blue callout contains 'Last triaged:' with date")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Weekly Standup Design Review Section
# =============================================================================
def _validate_weekly_standup_design_review(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Weekly Standup Template page with new Design Review Items section inserted between 'Write documentation' todo and 'Blockers' heading."""
    errors: list[str] = []

    checks_passed = []
    
    # Find Weekly Standup Template page
    try:
        standup_page = _find_page_by_title(final_state_backend, "Weekly Standup Template")
        if not standup_page:
            errors.append("[X] Weekly Standup Template page not found")
        else:
            checks_passed.append("[C] Weekly Standup Template page found")
    
        standup_id = standup_page.get("_id")
        standup_blocks = _get_blocks_for_page(final_state_backend, standup_id)
    
        # Sort blocks by order
        sorted_blocks = sorted(standup_blocks, key=lambda b: b.get("order", 0))
    
        # Find key blocks to verify positioning
        write_doc_todo_idx = None
        blockers_heading_idx = None
        design_review_heading_idx = None
    
        for i, block in enumerate(sorted_blocks):
            content = block.get("content", "").lower()
            block_type = block.get("type", "")
        
            # Find 'Write documentation for new API' todo
            if block_type in ["todo", "to_do", "checkbox"] and "write documentation" in content and "api" in content:
                write_doc_todo_idx = i
        
            # Find 'Blockers' heading
            if block_type in ["heading2", "heading_2"] and "blockers" in content:
                blockers_heading_idx = i
        
            # Find '🎨 Design Review Items' heading_3
            if block_type in ["heading3", "heading_3"] and "design review items" in content and "🎨" in block.get("content", ""):
                design_review_heading_idx = i
    
        if write_doc_todo_idx is None:
            errors.append("[X] Could not find 'Write documentation for new API' todo block")
        else:
            checks_passed.append("[C] Found 'Write documentation for new API' todo")
    
        if blockers_heading_idx is None:
            errors.append("[X] Could not find 'Blockers' heading")
        else:
            checks_passed.append("[C] Found 'Blockers' heading")
    
        # Check 1: Verify Design Review Items heading_3 exists with Yellow color
        if design_review_heading_idx is None:
            errors.append("[X] Missing heading_3 '🎨 Design Review Items'")
        else:
            checks_passed.append("[C] has heading_3 '🎨 Design Review Items'")
    
        design_heading_block = sorted_blocks[design_review_heading_idx]
        design_heading_content = design_heading_block.get("content", "")
    
        # Verify exact text with emoji
        if "🎨" not in design_heading_content or "design review items" not in design_heading_content.lower():
            errors.append(f"[X] heading_3 should have exact text '🎨 Design Review Items', found: '{design_heading_content}'")
        else:
            checks_passed.append(f"[C] heading_3 should have exact text '🎨 Design Review Items', found: '{design_heading_content}'")
    
        # Check for Yellow color property
        properties = design_heading_block.get("properties", {})
        color = properties.get("color", design_heading_block.get("color", ""))
        if not color or "yellow" not in color.lower():
            errors.append(f"[X] heading_3 '🎨 Design Review Items' should have Yellow color property, found: '{color}'")
        else:
            checks_passed.append(f"[C] heading_3 '🎨 Design Review Items' should have Yellow color property, found: '{color}'")
    
        checks_passed.append("[C] heading_3 '🎨 Design Review Items' with Yellow color present")
    
        # Check 2: Verify Design Review section is positioned correctly (after write_doc_todo, before blockers)
        if not (write_doc_todo_idx < design_review_heading_idx < blockers_heading_idx):
            errors.append(f"[X] Design Review section (position {design_review_heading_idx}) should be between 'Write documentation' todo (position {write_doc_todo_idx}) and 'Blockers' heading (position {blockers_heading_idx})")
        else:
            checks_passed.append(f"[C] Design Review section (position {design_review_heading_idx}) should be between 'Write documentation' todo (position {write_doc_todo_idx}) and 'Blockers' heading (position {blockers_heading_idx})")
    
        checks_passed.append("[C] Design Review section correctly positioned between 'Write documentation' todo and 'Blockers' heading")
    
        # Check 3: Verify three unchecked to-do blocks with exact emoji prefixes and text
        expected_todos = [
            ("👁️", "review new icon set proposals"),
            ("🎯", "approve color palette changes"),
            ("📐", "sign off on spacing system updates")
        ]
    
        # Look for todos between design review heading and blockers heading
        found_todos = []
        for i in range(design_review_heading_idx + 1, blockers_heading_idx):
            block = sorted_blocks[i]
            if block.get("type") in ["todo", "to_do", "checkbox"]:
                content = block.get("content", "")
                is_checked = block.get("properties", {}).get("checked", False)
                found_todos.append({
                    "content": content,
                    "checked": is_checked,
                    "index": i
                })
    
        if len(found_todos) < 3:
            errors.append(f"[X] Expected 3 unchecked to-do blocks under Design Review Items, found {len(found_todos)}")
        else:
            checks_passed.append(f"[C] Found 3 unchecked to-do blocks under Design Review Items as expected")
    
        # Verify each expected todo
        for emoji, expected_text in expected_todos:
            todo_found = False
            for todo in found_todos:
                content = todo["content"]
                if emoji in content and expected_text in content.lower():
                    if todo["checked"]:
                        errors.append(f"[X] Todo '{emoji} {expected_text}' should be unchecked")
                    else:
                        checks_passed.append(f"[C] Todo '{emoji} {expected_text}' should be unchecked")
                    todo_found = True
                    break
        
            if not todo_found:
                errors.append(f"[X] Missing unchecked todo with text '{emoji} {expected_text.title()}'")
            else:
                checks_passed.append(f"[C] has unchecked todo with text '{emoji} {expected_text.title()}'")
    
        checks_passed.append("[C] All three unchecked to-do blocks with correct emoji prefixes present")
    
        # Check 4: Verify callout with Gray background
        callout_found = False
        for i in range(design_review_heading_idx + 1, blockers_heading_idx):
            block = sorted_blocks[i]
            if block.get("type") == "callout":
                content = block.get("content", "")
                properties = block.get("properties", {})
                bg_color = properties.get("backgroundColor", block.get("backgroundColor", ""))
            
                has_gray_bg = "gray" in bg_color.lower() if bg_color else False
                has_eow_text = "design reviews due" in content.lower() and "eow" in content.lower()
            
                if has_gray_bg and has_eow_text:
                    callout_found = True
                    break
                elif has_gray_bg:
                    # Gray background found but wrong text
                    if "design reviews" not in content.lower() or "eow" not in content.lower():
                        errors.append(f"[X] Gray callout should have text 'Design reviews due by EOW', found: '{content}'")
                elif has_eow_text:
                    # Correct text but wrong background
                    errors.append(f"[X] Callout with 'Design reviews due by EOW' should have Gray background, found: '{bg_color}'")
                else:
                    checks_passed.append(f"[C] Callout with 'Design reviews due by EOW' should have Gray background, found: '{bg_color}'")
    
        if not callout_found:
            errors.append("[X] Missing callout with Gray background and text 'Design reviews due by EOW'")
        else:
            checks_passed.append("[C] has callout with Gray background and text 'Design reviews due by EOW'")
    
        checks_passed.append("[C] Callout with Gray background and 'Design reviews due by EOW' text present")
    
        # Check 5: Verify 'Blockers' heading has been shifted (should now be at order 12 or higher)
        blockers_block = sorted_blocks[blockers_heading_idx]
        blockers_order = blockers_block.get("order", 0)
    
        # Originally 'Blockers' was at order 8, with 5 new blocks it should be at 12 or higher
        # But we check the index position instead since order values might be renumbered
        # The blockers heading should now be at least 5 positions further than the original
        # Original: write_doc at idx X, blockers at idx X+1
        # New: write_doc at idx X, design_review at X+1, 3 todos, callout, blockers at X+6
    
        expected_min_gap = 5  # heading_3 + 3 todos + callout = 5 blocks
        actual_gap = blockers_heading_idx - write_doc_todo_idx - 1
    
        if actual_gap < expected_min_gap:
            errors.append(f"[X] Expected at least {expected_min_gap} blocks between 'Write documentation' todo and 'Blockers' heading, found {actual_gap}")
        else:
            checks_passed.append(f"[C] Expected at least {expected_min_gap} blocks between 'Write documentation' todo and 'Blockers' heading, found {actual_gap}")
    
        checks_passed.append(f"[C] 'Blockers' heading correctly shifted ({actual_gap} blocks inserted before it)")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Sprint Metrics Action Items Summary
# =============================================================================
def _validate_sprint_metrics_action_items(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Sprint Metrics section added to Sprint Planning - Jan 15 page with task statistics."""
    errors: list[str] = []

    checks_passed = []
    
    # Find Sprint Planning - Jan 15 page
    try:
        sprint_planning = _find_page_by_title(final_state_backend, "Sprint Planning - Jan 15")
        if not sprint_planning:
            errors.append("[X] Sprint Planning - Jan 15 page not found")
        else:
            checks_passed.append("[C] Sprint Planning - Jan 15 page found")
    
        sprint_planning_id = sprint_planning.get("_id")
        page_blocks = _get_blocks_for_page(final_state_backend, sprint_planning_id)
    
        # Sort blocks by order
        sorted_blocks = sorted(page_blocks, key=lambda b: b.get("order", 0))
    
        # Find the Action Items heading
        action_items_idx = None
        for i, block in enumerate(sorted_blocks):
            if block.get("type") in ["heading2", "heading_2"] and "action items" in block.get("content", "").lower():
                action_items_idx = i
                break
    
        if action_items_idx is None:
            errors.append("[X] Action Items section not found")
        else:
            checks_passed.append("[C] Action Items section found")
    
        checks_passed.append("[C] Action Items section found")
    
        # Find all todo blocks after Action Items heading
        todo_blocks = []
        for i in range(action_items_idx + 1, len(sorted_blocks)):
            block = sorted_blocks[i]
            block_type = block.get("type", "")
            # Stop if we hit another heading (end of Action Items section)
            if block_type in ["heading1", "heading2", "heading_1", "heading_2"] and "sprint metrics" not in block.get("content", "").lower():
                break
            if block_type in ["todo", "to_do", "checkbox"]:
                todo_blocks.append(block)
    
        # Count original todos (should be 2: Alice and Bob tasks)
        original_todo_count = len([b for b in todo_blocks if "alice" in b.get("content", "").lower() or "bob" in b.get("content", "").lower()])
        if original_todo_count < 2:
            # Fall back to total count if names not found
            original_todo_count = len(todo_blocks) if len(todo_blocks) >= 2 else 2
    
        checked_count = sum(1 for t in todo_blocks if t.get("properties", {}).get("checked", False))
    
        checks_passed.append(f"[C] Found {len(todo_blocks)} todo blocks in Action Items section")
    
        # Check 1: Find 'Sprint Metrics' heading_2 with emoji
        sprint_metrics_idx = None
        sprint_metrics_block = None
        for i, block in enumerate(sorted_blocks):
            if block.get("type") in ["heading2", "heading_2"]:
                content = block.get("content", "")
                if "sprint metrics" in content.lower() and "📋" in content:
                    sprint_metrics_idx = i
                    sprint_metrics_block = block
                    break
    
        if sprint_metrics_idx is None:
            errors.append("[X] Missing heading_2 '📋 Sprint Metrics'")
        else:
            checks_passed.append("[C] has heading_2 '📋 Sprint Metrics'")
    
        checks_passed.append("[C] Heading_2 '📋 Sprint Metrics' present")
    
        # Verify Sprint Metrics appears after the todo blocks (after Action Items section todos)
        last_todo_idx = None
        for i in range(action_items_idx + 1, len(sorted_blocks)):
            block = sorted_blocks[i]
            if block.get("type") in ["todo", "to_do", "checkbox"]:
                last_todo_idx = i
            elif block.get("type") in ["heading2", "heading_2"] and "sprint metrics" in block.get("content", "").lower():
                break
    
        if last_todo_idx is not None and sprint_metrics_idx <= last_todo_idx:
            errors.append("[X] 'Sprint Metrics' heading should appear AFTER all to-do items in Action Items section")
        else:
            checks_passed.append("[C] 'Sprint Metrics' heading should appear AFTER all to-do items in Action Items section")
    
        checks_passed.append("[C] 'Sprint Metrics' heading positioned after all todos")
    
        # Check 2: Find callout with Yellow background and no icon
        callout_found = False
        callout_block = None
        callout_idx = None
    
        for i in range(sprint_metrics_idx + 1, len(sorted_blocks)):
            block = sorted_blocks[i]
            if block.get("type") == "callout":
                properties = block.get("properties", {})
                bg_color = properties.get("backgroundColor", block.get("backgroundColor", ""))
                icon = properties.get("icon", block.get("icon", ""))
            
                has_yellow_bg = "yellow" in bg_color.lower() if bg_color else False
                has_no_icon = not icon or icon == "" or icon == "none" or icon is None
            
                if has_yellow_bg:
                    callout_found = True
                    callout_block = block
                    callout_idx = i
                
                    if not has_no_icon:
                        errors.append(f"[X] Callout should have no icon, found: '{icon}'")
                    else:
                        checks_passed.append(f"[C] Callout should have icon, found: '{icon}'")
                    break
    
        if not callout_found:
            errors.append("[X] Callout with Yellow background not found after Sprint Metrics heading")
        else:
            checks_passed.append("[C] Callout with Yellow background found after Sprint Metrics heading")
    
        checks_passed.append("[C] Callout with Yellow background and no icon present")
    
        # Check 3: Find heading_3 'Task Summary' (can be inside or after callout)
        task_summary_found = False
        for i in range(sprint_metrics_idx + 1, len(sorted_blocks)):
            block = sorted_blocks[i]
            if block.get("type") in ["heading3", "heading_3"]:
                content = block.get("content", "").lower()
                if "task summary" in content:
                    task_summary_found = True
                    break
    
        if not task_summary_found:
            errors.append("[X] Missing heading_3 'Task Summary'")
        else:
            checks_passed.append("[C] has heading_3 'Task Summary'")
    
        checks_passed.append("[C] Heading_3 'Task Summary' present")
    
        # Check 4: Find numbered list with correct statistics
        numbered_items = []
        for i in range(sprint_metrics_idx + 1, len(sorted_blocks)):
            block = sorted_blocks[i]
            if block.get("type") in ["numberedList", "numbered_list", "numbered_list_item", "numbered"]:
                numbered_items.append(block)
    
        if len(numbered_items) < 4:
            errors.append(f"[X] Expected 4 numbered list items, found {len(numbered_items)}")
        else:
            checks_passed.append(f"[C] Found 4 numbered list items as expected")
    
        # Verify the numbered list content
        all_numbered_content = " ".join([item.get("content", "") for item in numbered_items]).lower()
    
        # Check for Total Action Items
        if "total action items" not in all_numbered_content:
            errors.append("[X] Numbered list missing 'Total Action Items' entry")
        else:
            checks_passed.append("[C] Numbered list has 'Total Action Items' entry")
    
        # Check for Completed with percentage
        if "completed" not in all_numbered_content or "%" not in all_numbered_content:
            errors.append("[X] Numbered list missing 'Completed' entry with percentage")
        else:
            checks_passed.append("[C] Numbered list has 'Completed' entry with percentage")
    
        # Check for Alice assignment
        if "alice" not in all_numbered_content:
            errors.append("[X] Numbered list missing 'Assigned to Alice' entry")
        else:
            checks_passed.append("[C] Numbered list has 'Assigned to Alice' entry")
    
        # Check for Bob assignment
        if "bob" not in all_numbered_content:
            errors.append("[X] Numbered list missing 'Assigned to Bob' entry")
        else:
            checks_passed.append("[C] Numbered list has 'Assigned to Bob' entry")
    
        checks_passed.append("[C] Numbered list with correct statistics present (Total, Completed %, Alice, Bob)")
    
        # Check 5: Find quote block with exact text
        quote_found = False
        expected_quote = "sprint velocity tracking helps improve future estimations"
    
        for i in range(sprint_metrics_idx + 1, len(sorted_blocks)):
            block = sorted_blocks[i]
            if block.get("type") == "quote":
                content = block.get("content", "").lower()
                if expected_quote in content:
                    quote_found = True
                    break
    
        if not quote_found:
            errors.append("[X] Missing quote block with text 'Sprint velocity tracking helps improve future estimations.'")
        else:
            checks_passed.append("[C] has quote block with text 'Sprint velocity tracking helps improve future estimations.'")
    
        checks_passed.append("[C] Quote block with velocity tracking text present")
    
        # Verify quote appears after callout
        quote_idx = None
        for i in range(len(sorted_blocks)):
            block = sorted_blocks[i]
            if block.get("type") == "quote" and expected_quote in block.get("content", "").lower():
                quote_idx = i
                break
    
        if callout_idx is not None and quote_idx is not None and quote_idx < callout_idx:
            errors.append("[X] Quote block should appear after the callout")
        else:
            checks_passed.append("[C] Quote block should appear after the callout")
    
        checks_passed.append("[C] Quote block correctly positioned after callout")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Weekly Progress Metrics Dashboard
# =============================================================================
def _validate_weekly_progress_metrics(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Weekly Progress Metrics section added to Weekly Standup Template page."""
    errors: list[str] = []

    checks_passed = []
    
    # Find Weekly Standup Template page
    try:
        weekly_standup = _find_page_by_title(final_state_backend, "Weekly Standup Template")
        if not weekly_standup:
            errors.append("[X] Weekly Standup Template page not found")
        else:
            checks_passed.append("[C] Weekly Standup Template page found")
    
        weekly_standup_id = weekly_standup.get("_id")
        page_blocks = _get_blocks_for_page(final_state_backend, weekly_standup_id)
    
        # Sort blocks by order
        sorted_blocks = sorted(page_blocks, key=lambda b: b.get("order", 0))
    
        # Count all todo blocks on the page
        todo_blocks = [b for b in sorted_blocks if b.get("type") in ["todo", "to_do", "checkbox"]]
        total_todos = len(todo_blocks)
        checked_todos = sum(1 for t in todo_blocks if t.get("properties", {}).get("checked", False))
        unchecked_todos = total_todos - checked_todos
        percentage = round((checked_todos / total_todos * 100) if total_todos > 0 else 0)
    
        checks_passed.append(f"[C] Found {total_todos} todos ({checked_todos} checked, {unchecked_todos} pending)")
    
        # Find Blockers section and count blockers
        blockers_idx = None
        for i, block in enumerate(sorted_blocks):
            if block.get("type") in ["heading2", "heading_2"] and "blockers" in block.get("content", "").lower():
                blockers_idx = i
                break
    
        if blockers_idx is None:
            errors.append("[X] Blockers section not found")
        else:
            checks_passed.append("[C] Blockers section found")
    
        # Count blocker todos (todos after Blockers heading until next section)
        blocker_count = 0
        for i in range(blockers_idx + 1, len(sorted_blocks)):
            block = sorted_blocks[i]
            block_type = block.get("type", "")
            # Stop if we hit another heading (end of Blockers section)
            if block_type in ["heading1", "heading2", "heading_1", "heading_2"] and "weekly progress metrics" not in block.get("content", "").lower():
                break
            if block_type in ["todo", "to_do", "checkbox"]:
                blocker_count += 1
    
        checks_passed.append(f"[C] Blockers section found with {blocker_count} blocker(s)")
    
        # Check 1: Find 'Weekly Progress Metrics' heading_2 with emoji
        metrics_heading_idx = None
        for i, block in enumerate(sorted_blocks):
            if block.get("type") in ["heading2", "heading_2"]:
                content = block.get("content", "")
                if "weekly progress metrics" in content.lower() and "📊" in content:
                    metrics_heading_idx = i
                    break
    
        if metrics_heading_idx is None:
            errors.append("[X] Missing heading_2 '📊 Weekly Progress Metrics'")
        else:
            checks_passed.append("[C] has heading_2 '📊 Weekly Progress Metrics'")
    
        checks_passed.append("[C] Heading_2 '📊 Weekly Progress Metrics' present")
    
        # Verify metrics heading appears after Blockers section
        # Find the last block of Blockers section (before metrics heading)
        last_blocker_section_idx = blockers_idx
        for i in range(blockers_idx + 1, len(sorted_blocks)):
            block = sorted_blocks[i]
            block_type = block.get("type", "")
            if block_type in ["heading1", "heading2", "heading_1", "heading_2"]:
                break
            last_blocker_section_idx = i
    
        if metrics_heading_idx <= last_blocker_section_idx:
            errors.append("[X] 'Weekly Progress Metrics' heading should appear AFTER the Blockers section")
        else:
            checks_passed.append("[C] 'Weekly Progress Metrics' heading should appear AFTER the Blockers section")
    
        checks_passed.append("[C] 'Weekly Progress Metrics' section positioned after Blockers")
    
        # Check 2: Find callout with Yellow background and no icon
        callout_found = False
        callout_idx = None
    
        for i in range(metrics_heading_idx + 1, len(sorted_blocks)):
            block = sorted_blocks[i]
            if block.get("type") == "callout":
                properties = block.get("properties", {})
                bg_color = properties.get("backgroundColor", block.get("backgroundColor", ""))
                icon = properties.get("icon", block.get("icon", ""))
            
                has_yellow_bg = "yellow" in bg_color.lower() if bg_color else False
                has_no_icon = not icon or icon == "" or icon == "none" or icon is None
            
                if has_yellow_bg:
                    callout_found = True
                    callout_idx = i
                
                    if not has_no_icon:
                        errors.append(f"[X] Callout should have no icon, found: '{icon}'")
                    else:
                        checks_passed.append(f"[C] Callout should have icon, found: '{icon}'")
                    break
    
        if not callout_found:
            errors.append("[X] Callout with Yellow background not found after Weekly Progress Metrics heading")
        else:
            checks_passed.append("[C] Callout with Yellow background found after Weekly Progress Metrics heading")
    
        checks_passed.append("[C] Callout with Yellow background and no icon present")
    
        # Check 3: Find bold paragraph 'Task Completion Statistics'
        stats_paragraph_found = False
        for i in range(metrics_heading_idx + 1, len(sorted_blocks)):
            block = sorted_blocks[i]
            if block.get("type") in ["paragraph", "text"]:
                content = block.get("content", "").lower()
                if "task completion statistics" in content:
                    stats_paragraph_found = True
                    break
    
        if not stats_paragraph_found:
            # Check if it's in the callout content
            if callout_idx is not None:
                callout_content = sorted_blocks[callout_idx].get("content", "").lower()
                if "task completion statistics" in callout_content:
                    stats_paragraph_found = True
    
        if not stats_paragraph_found:
            errors.append("[X] Missing bold paragraph 'Task Completion Statistics'")
        else:
            checks_passed.append("[C] has bold paragraph 'Task Completion Statistics'")
    
        checks_passed.append("[C] Bold paragraph 'Task Completion Statistics' present")
    
        # Check 4: Find bulleted list with correct statistics
        bulleted_items = []
        for i in range(metrics_heading_idx + 1, len(sorted_blocks)):
            block = sorted_blocks[i]
            if block.get("type") in ["bulletedList", "bulleted_list", "bulleted_list_item", "bulleted"]:
                bulleted_items.append(block)
    
        if len(bulleted_items) < 4:
            errors.append(f"[X] Expected 4 bulleted list items, found {len(bulleted_items)}")
        else:
            checks_passed.append(f"[C] Found 4 bulleted list items as expected")
    
        # Verify the bulleted list content
        all_bullet_content = " ".join([item.get("content", "") for item in bulleted_items]).lower()
    
        # Check for Total tasks tracked
        if "total tasks tracked" not in all_bullet_content:
            errors.append("[X] Bulleted list missing 'Total tasks tracked' entry")
        else:
            checks_passed.append("[C] Bulleted list has 'Total tasks tracked' entry")
    
        # Check for Tasks completed with percentage
        if "tasks completed" not in all_bullet_content or "%" not in all_bullet_content:
            errors.append("[X] Bulleted list missing 'Tasks completed' entry with percentage")
        else:
            checks_passed.append("[C] Bulleted list has 'Tasks completed' entry with percentage")
    
        # Check for Tasks pending
        if "tasks pending" not in all_bullet_content:
            errors.append("[X] Bulleted list missing 'Tasks pending' entry")
        else:
            checks_passed.append("[C] Bulleted list has 'Tasks pending' entry")
    
        # Check for Blockers identified
        if "blockers identified" not in all_bullet_content:
            errors.append("[X] Bulleted list missing 'Blockers identified' entry")
        else:
            checks_passed.append("[C] Bulleted list has 'Blockers identified' entry")
    
        checks_passed.append("[C] Bulleted list with all statistics present (Total, Completed %, Pending, Blockers)")
    
        # Check 5: Find divider
        divider_found = False
        divider_idx = None
        for i in range(metrics_heading_idx + 1, len(sorted_blocks)):
            block = sorted_blocks[i]
            if block.get("type") == "divider":
                divider_found = True
                divider_idx = i
                break
    
        if not divider_found:
            errors.append("[X] Missing divider after the callout/statistics")
        else:
            checks_passed.append("[C] has divider after the callout/statistics")
    
        checks_passed.append("[C] Divider present")
    
        # Check 6: Find quote block with exact text
        quote_found = False
        expected_quote = "success is the sum of small efforts repeated day in and day out"
    
        for i in range(metrics_heading_idx + 1, len(sorted_blocks)):
            block = sorted_blocks[i]
            if block.get("type") == "quote":
                content = block.get("content", "").lower()
                if expected_quote in content:
                    quote_found = True
                    break
    
        if not quote_found:
            errors.append("[X] Missing quote block with text 'Success is the sum of small efforts repeated day in and day out.'")
        else:
            checks_passed.append("[C] has quote block with text 'Success is the sum of small efforts repeated day in and day out.'")
    
        checks_passed.append("[C] Quote block with motivational text present")
    
        # Verify quote appears after divider
        quote_idx = None
        for i in range(len(sorted_blocks)):
            block = sorted_blocks[i]
            if block.get("type") == "quote" and expected_quote in block.get("content", "").lower():
                quote_idx = i
                break
    
        if divider_idx is not None and quote_idx is not None and quote_idx < divider_idx:
            errors.append("[X] Quote block should appear after the divider")
        else:
            checks_passed.append("[C] Quote block should appear after the divider")
    
        checks_passed.append("[C] Quote block correctly positioned after divider")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Sprint Retrospective Analysis
# =============================================================================
def _validate_sprint_retrospective_analysis(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Sprint Retrospective Analysis page with content from Sprint Planning and Team Retrospective."""
    errors: list[str] = []

    checks_passed = []
    
    # Find Meeting Notes parent page
    try:
        meeting_notes = _find_page_by_title(final_state_backend, "Meeting Notes")
        if not meeting_notes:
            errors.append("[X] Meeting Notes page not found")
        else:
            checks_passed.append("[C] Meeting Notes page found")
    
        meeting_notes_id = meeting_notes.get("_id")
    
        # Find Sprint Planning page to extract data
        sprint_planning = _find_page_by_title(final_state_backend, "Sprint Planning - Jan 15")
        if not sprint_planning:
            sprint_planning = _find_page_by_title(final_state_backend, "Sprint Planning")
        if not sprint_planning:
            errors.append("[X] Sprint Planning page not found")
        else:
            checks_passed.append("[C] Sprint Planning page found")
    
        sprint_planning_id = sprint_planning.get("_id")
        sprint_planning_blocks = _get_blocks_for_page(final_state_backend, sprint_planning_id)
    
        # Find Team Retrospective page
        team_retro = _find_page_by_title(final_state_backend, "Team Retrospective")
        if not team_retro:
            errors.append("[X] Team Retrospective page not found")
        else:
            checks_passed.append("[C] Team Retrospective page found")
    
        team_retro_id = team_retro.get("_id")
    
        # Count todos across both meetings - using query-level filtering
        sprint_todos = [b for b in sprint_planning_blocks if b.get("type") in ["todo", "to_do", "checkbox"]]
        retro_todos = _get_todo_blocks(final_state_backend, team_retro_id)
        total_action_items = len(sprint_todos) + len(retro_todos)
    
        # Extract sprint goals from Sprint Planning (numbered list items)
        sprint_goals = []
        for block in sprint_planning_blocks:
            if block.get("type") in ["numberedList", "numbered_list", "numbered_list_item", "numbered"]:
                content = block.get("content", "")
                if content:
                    sprint_goals.append(content)
    
        # Count attendees (bulleted list items under "Attendees" section)
        attendee_count = 0
        in_attendees_section = False
        sorted_sprint_blocks = sorted(sprint_planning_blocks, key=lambda b: b.get("order", 0))
        for block in sorted_sprint_blocks:
            block_type = block.get("type", "")
            content = block.get("content", "").lower()
        
            if block_type in ["heading2", "heading_2"] and "attendees" in content:
                in_attendees_section = True
                continue
            if in_attendees_section and block_type in ["heading2", "heading_2", "heading1", "heading_1"]:
                in_attendees_section = False
                continue
            if in_attendees_section and block_type in ["bulletedList", "bulleted_list", "bulleted_list_item", "bulleted"]:
                attendee_count += 1
    
        checks_passed.append(f"[C] Source data found: {len(sprint_goals)} sprint goals, {total_action_items} action items, {attendee_count} attendees")
    
        # Check for Sprint Retrospective Analysis page as child of Meeting Notes
        child_pages = _get_child_pages(final_state_backend, meeting_notes_id)
        analysis_page = None
        for page in child_pages:
            title = page.get("title", "").lower()
            if "sprint retrospective analysis" in title:
                analysis_page = page
                break
    
        if not analysis_page:
            errors.append("[X] Sprint Retrospective Analysis page not found as child of Meeting Notes")
        else:
            checks_passed.append("[C] Sprint Retrospective Analysis page found as child of Meeting Notes")
    
        # Verify parent relationship
        if analysis_page.get("parentId") != meeting_notes_id:
            errors.append("[X] Sprint Retrospective Analysis is not a child of Meeting Notes")
        else:
            checks_passed.append("[C] Sprint Retrospective Analysis is a child of Meeting Notes")
    
        checks_passed.append("[C] Sprint Retrospective Analysis page created as child of Meeting Notes")
    
        analysis_page_id = analysis_page.get("_id")
        analysis_blocks = _get_blocks_for_page(final_state_backend, analysis_page_id)
        sorted_blocks = sorted(analysis_blocks, key=lambda b: b.get("order", 0))
    
        # Check 1: heading_1 '🔍 Sprint Retrospective Analysis'
        has_main_heading = any(
            b.get("type") in ["heading1", "heading_1"] and 
            "sprint retrospective analysis" in b.get("content", "").lower() and 
            "🔍" in b.get("content", "")
            for b in sorted_blocks
        )
        if not has_main_heading:
            errors.append("[X] Missing heading_1 '🔍 Sprint Retrospective Analysis'")
        else:
            checks_passed.append("[C] Heading_1 '🔍 Sprint Retrospective Analysis' present")
    
        # Check 2: heading_2 '📊 Sprint Overview'
        has_overview_heading = any(
            b.get("type") in ["heading2", "heading_2"] and 
            "sprint overview" in b.get("content", "").lower() and 
            "📊" in b.get("content", "")
            for b in sorted_blocks
        )
        if not has_overview_heading:
            errors.append("[X] Missing heading_2 '📊 Sprint Overview'")
        else:
            checks_passed.append("[C] Heading_2 '📊 Sprint Overview' present")
    
        # Check 3: Callout with yellow_background containing sprint dates and team size
        callout_found = False
        callout_has_duration = False
        callout_has_team_size = False
    
        for block in sorted_blocks:
            if block.get("type") == "callout":
                properties = block.get("properties", {})
                bg_color = properties.get("backgroundColor", block.get("backgroundColor", ""))
                content = block.get("content", "")
            
                has_yellow_bg = "yellow" in bg_color.lower() if bg_color else False
            
                if has_yellow_bg:
                    callout_found = True
                    # Check for sprint duration
                    if "january 15" in content.lower() and ("29" in content or "2024" in content):
                        callout_has_duration = True
                    # Check for team size (should be 3)
                    if "team size" in content.lower() and "3" in content:
                        callout_has_team_size = True
                    break
    
        if not callout_found:
            errors.append("[X] Callout with yellow_background not found")
        else:
            checks_passed.append("[C] Callout with yellow_background found")
        if not callout_has_duration:
            errors.append("[X] Callout missing 'Sprint Duration: January 15-29, 2024'")
        else:
            checks_passed.append("[C] Callout has 'Sprint Duration: January 15-29, 2024'")
        if not callout_has_team_size:
            errors.append("[X] Callout missing 'Team Size: 3 members'")
        else:
            checks_passed.append("[C] Callout has 'Team Size: 3 members'")
    
        checks_passed.append("[C] Callout with yellow_background containing sprint dates and team size present")
    
        # Check 4: heading_2 '🎯 Goal Achievement'
        has_goal_heading = any(
            b.get("type") in ["heading2", "heading_2"] and 
            "goal achievement" in b.get("content", "").lower() and 
            "🎯" in b.get("content", "")
            for b in sorted_blocks
        )
        if not has_goal_heading:
            errors.append("[X] Missing heading_2 '🎯 Goal Achievement'")
        else:
            checks_passed.append("[C] Heading_2 '🎯 Goal Achievement' present")
    
        # Check 5: Paragraph 'Based on Sprint Planning goals:'
        has_goals_intro = any(
            b.get("type") in ["paragraph", "text"] and 
            "based on sprint planning goals" in b.get("content", "").lower()
            for b in sorted_blocks
        )
        if not has_goals_intro:
            errors.append("[X] Missing paragraph 'Based on Sprint Planning goals:'")
        else:
            checks_passed.append("[C] Paragraph 'Based on Sprint Planning goals:' present")
    
        # Check 6: Numbered list with 3 goals, each with ' - Status: [PENDING REVIEW]'
        numbered_items = [
            b for b in sorted_blocks 
            if b.get("type") in ["numberedList", "numbered_list", "numbered_list_item", "numbered"]
        ]
    
        # Should have at least 3 numbered items (the 3 sprint goals)
        if len(numbered_items) < 3:
            errors.append(f"[X] Expected at least 3 numbered list items for sprint goals, found {len(numbered_items)}")
        else:
            checks_passed.append(f"[C] Found at least 3 numbered list items for sprint goals ({len(numbered_items)})")
    
        # Check that each goal has ' - Status: [PENDING REVIEW]'
        goals_with_status = 0
        for item in numbered_items:
            content = item.get("content", "")
            if "status" in content.lower() and "pending review" in content.lower():
                goals_with_status += 1
    
        if goals_with_status < 3:
            errors.append(f"[X] Expected 3 goals with ' - Status: [PENDING REVIEW]', found {goals_with_status}")
        else:
            checks_passed.append(f"[C] Found 3 goals with ' - Status: [PENDING REVIEW]' as expected")
    
        checks_passed.append("[C] 3 sprint goals listed with ' - Status: [PENDING REVIEW]'")
    
        # Check 7: heading_2 '📈 Action Items Summary'
        has_action_heading = any(
            b.get("type") in ["heading2", "heading_2"] and 
            "action items summary" in b.get("content", "").lower() and 
            "📈" in b.get("content", "")
            for b in sorted_blocks
        )
        if not has_action_heading:
            errors.append("[X] Missing heading_2 '📈 Action Items Summary'")
        else:
            checks_passed.append("[C] Heading_2 '📈 Action Items Summary' present")
    
        # Check 8: Paragraph with action items count
        action_count_found = False
        for block in sorted_blocks:
            if block.get("type") in ["paragraph", "text"]:
                content = block.get("content", "").lower()
                if "total action items tracked" in content:
                    # Check if the count matches (should be 2 from initial data)
                    if str(total_action_items) in content:
                        action_count_found = True
                    else:
                        # Allow any number since the agent may have counted differently
                        action_count_found = True
                    break
    
        if not action_count_found:
            errors.append("[X] Missing paragraph 'Total action items tracked: [COUNT]'")
        else:
            checks_passed.append(f"[C] Action items count paragraph present (expected count: {total_action_items})")
    
        # Check 9: heading_2 '🚀 Next Steps'
        has_next_steps_heading = any(
            b.get("type") in ["heading2", "heading_2"] and 
            "next steps" in b.get("content", "").lower() and 
            "🚀" in b.get("content", "")
            for b in sorted_blocks
        )
        if not has_next_steps_heading:
            errors.append("[X] Missing heading_2 '🚀 Next Steps'")
        else:
            checks_passed.append("[C] Heading_2 '🚀 Next Steps' present")
    
        # Check 10: Three unchecked todos with specified content
        todo_blocks = [
            b for b in sorted_blocks 
            if b.get("type") in ["todo", "to_do", "checkbox"]
        ]
    
        # Should have at least 3 todos
        if len(todo_blocks) < 3:
            errors.append(f"[X] Expected 3 todo items in Next Steps, found {len(todo_blocks)}")
        else:
            checks_passed.append(f"[C] Found 3 todo items in Next Steps as expected")
    
        # Check for the specific todo items
        expected_todos = [
            ("📝", "schedule follow-up meeting"),
            ("🔄", "update project roadmap"),
            ("📊", "prepare metrics dashboard")
        ]
    
        found_todos = 0
        for emoji, text in expected_todos:
            for todo in todo_blocks:
                content = todo.get("content", "")
                if emoji in content and text in content.lower():
                    # Check that it's unchecked
                    properties = todo.get("properties", {})
                    is_checked = properties.get("checked", False)
                    if not is_checked:
                        found_todos += 1
                    break
    
        if found_todos < 3:
            errors.append(f"[X] Expected 3 unchecked todos with specified text and emojis, found {found_todos}")
        else:
            checks_passed.append(f"[C] Found 3 unchecked todos with specified text and emojis as expected")
    
        checks_passed.append("[C] 3 unchecked todo items with correct emojis and text present")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Sprint Summary Dashboard
# =============================================================================
def _validate_sprint_summary_dashboard(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Sprint Summary Dashboard page with meeting analysis and todo statistics."""
    errors: list[str] = []

    checks_passed = []
    
    # Find Meeting Notes parent page
    try:
        meeting_notes = _find_page_by_title(final_state_backend, "Meeting Notes")
        if not meeting_notes:
            errors.append("[X] Meeting Notes page not found")
        else:
            checks_passed.append("[C] Meeting Notes page found")
    
        meeting_notes_id = meeting_notes.get("_id")
    
        # Get child pages under Meeting Notes (excluding the dashboard itself)
        meeting_children = _get_child_pages(final_state_backend, meeting_notes_id)
        meeting_pages = [
            p for p in meeting_children 
            if "sprint summary dashboard" not in p.get("title", "").lower()
        ]
    
        # Expected meeting pages: Sprint Planning - Jan 15, Team Retrospective
        expected_meeting_count = 2
    
        if len(meeting_pages) < expected_meeting_count:
            errors.append(f"[X] Expected at least {expected_meeting_count} meeting pages under Meeting Notes, found {len(meeting_pages)}")
        else:
            checks_passed.append(f"[C] Found {len(meeting_pages)} meeting pages under Meeting Notes")
    
        # Find Sprint Summary Dashboard page as child of Meeting Notes
        dashboard = None
        for page in meeting_children:
            title = page.get("title", "").lower()
            if "sprint summary dashboard" in title:
                dashboard = page
                break
    
        if not dashboard:
            errors.append("[X] Sprint Summary Dashboard page not found as child of Meeting Notes")
        else:
            checks_passed.append("[C] Sprint Summary Dashboard page found as child of Meeting Notes")
    
        # Verify it's a child of Meeting Notes
        if dashboard.get("parentId") != meeting_notes_id:
            errors.append("[X] Sprint Summary Dashboard is not a child of Meeting Notes")
        else:
            checks_passed.append("[C] Sprint Summary Dashboard created under Meeting Notes")
    
        dashboard_id = dashboard.get("_id")
        dashboard_blocks = _get_blocks_for_page(final_state_backend, dashboard_id)
    
        # Sort blocks by order
        sorted_blocks = sorted(dashboard_blocks, key=lambda b: b.get("order", 0))
    
        # Check 1: heading_1 '🚀 Sprint Summary Dashboard'
        found_main_heading = any(
            b.get("type") in ["heading1", "heading_1"] and
            "🚀" in b.get("content", "") and
            "sprint summary dashboard" in b.get("content", "").lower()
            for b in sorted_blocks
        )
        if not found_main_heading:
            errors.append("[X] Missing heading_1 '🚀 Sprint Summary Dashboard'")
        else:
            checks_passed.append("[C] Heading_1 '🚀 Sprint Summary Dashboard' present")
    
        # Check 2: heading_2 '📅 Meeting Overview'
        found_overview_heading = any(
            b.get("type") in ["heading2", "heading_2"] and
            "📅" in b.get("content", "") and
            "meeting overview" in b.get("content", "").lower()
            for b in sorted_blocks
        )
        if not found_overview_heading:
            errors.append("[X] Missing heading_2 '📅 Meeting Overview'")
        else:
            checks_passed.append("[C] Heading_2 '📅 Meeting Overview' present")
    
        # Check 3: Paragraph with 'Total meetings analyzed: [X]'
        paragraph_blocks = [
            b for b in sorted_blocks 
            if b.get("type") in ["paragraph", "text"]
        ]
    
        found_total_meetings = False
        for p in paragraph_blocks:
            content = p.get("content", "").lower()
            if "total meetings analyzed" in content:
                # Verify count matches expected (2)
                if str(expected_meeting_count) in content or f": {expected_meeting_count}" in p.get("content", ""):
                    found_total_meetings = True
                    break
    
        if not found_total_meetings:
            errors.append(f"[X] Missing paragraph 'Total meetings analyzed: {expected_meeting_count}'")
        else:
            checks_passed.append(f"[C] Total meetings paragraph shows {expected_meeting_count}")
    
        # Get todo statistics for each meeting page
        meeting_stats = {}
        for meeting_page in meeting_pages:
            page_id = meeting_page.get("_id")
            page_title = meeting_page.get("title", "")
            page_blocks = _get_blocks_for_page(final_state_backend, page_id)
        
            todo_blocks = [
                b for b in page_blocks 
                if b.get("type") in ["todo", "to_do", "checkbox"]
            ]
            total_todos = len(todo_blocks)
            checked_todos = sum(
                1 for t in todo_blocks 
                if t.get("properties", {}).get("checked", False)
            )
            completion_rate = round((checked_todos / total_todos * 100) if total_todos > 0 else 0)
        
            meeting_stats[page_title] = {
                "total": total_todos,
                "checked": checked_todos,
                "completion_rate": completion_rate
            }
    
        # Check 4: For each meeting, verify heading_3 '🔹 [Page Title]'
        heading3_blocks = [
            b for b in sorted_blocks 
            if b.get("type") in ["heading3", "heading_3"]
        ]
    
        meetings_with_heading = 0
        for meeting_page in meeting_pages:
            meeting_title = meeting_page.get("title", "")
            for h in heading3_blocks:
                content = h.get("content", "")
                if "🔹" in content and any(
                    word.lower() in content.lower() 
                    for word in meeting_title.split()[:3] if len(word) > 2
                ):
                    meetings_with_heading += 1
                    break
    
        if meetings_with_heading < len(meeting_pages):
            errors.append(f"[X] Missing heading_3 blocks for meeting pages (found {meetings_with_heading}, expected {len(meeting_pages)})")
        else:
            checks_passed.append(f"[C] All {len(meeting_pages)} meeting pages have heading_3 with '🔹' prefix")
    
        # Check 5: For each meeting, verify callout with gray background
        callout_blocks = [
            b for b in sorted_blocks 
            if b.get("type") == "callout"
        ]
    
        gray_callouts_found = 0
        callout_with_stats = 0
    
        for callout in callout_blocks:
            bg_color = callout.get("backgroundColor", "")
            properties = callout.get("properties", {})
            prop_bg = properties.get("backgroundColor", "")
            content = callout.get("content", "").lower()
        
            # Check for gray background
            is_gray = any("gray" in c.lower() for c in [bg_color, prop_bg] if c)
        
            if is_gray:
                gray_callouts_found += 1
            
                # Check for action items count and completion rate
                has_action_items = "total action items" in content or "action items:" in content
                has_completion_rate = "completion rate" in content and "%" in content
            
                if has_action_items or has_completion_rate:
                    callout_with_stats += 1
    
        if gray_callouts_found < len(meeting_pages):
            errors.append(f"[X] Expected {len(meeting_pages)} gray callouts (one per meeting), found {gray_callouts_found}")
        else:
            checks_passed.append(f"[C] Found {gray_callouts_found} gray callouts")
    
        if callout_with_stats < len(meeting_pages):
            errors.append(f"[X] Callouts should contain 'Total action items' and 'Completion rate' statistics")
        else:
            checks_passed.append("[C] Callouts contain action items count and completion rate")
    
        # Check 6: Verify Sprint Planning statistics (100% completion, 2 action items)
        sprint_planning_page = None
        for meeting_page in meeting_pages:
            title = meeting_page.get("title", "").lower()
            if "sprint planning" in title:
                sprint_planning_page = meeting_page
                break
    
        if sprint_planning_page:
            sprint_title = sprint_planning_page.get("title", "")
            stats = meeting_stats.get(sprint_title, {})
            expected_total = 2
            expected_rate = 100
        
            # Verify the stats are correct
            if stats.get("total", 0) != expected_total:
                errors.append(f"[X] Sprint Planning should have {expected_total} total action items, found {stats.get('total', 0)}")
            else:
                checks_passed.append(f"[C] Sprint Planning should have {expected_total} total action items, found {stats.get('total', 0)}")
            if stats.get("completion_rate", 0) != expected_rate:
                errors.append(f"[X] Sprint Planning should have {expected_rate}% completion rate, found {stats.get('completion_rate', 0)}%")
            else:
                checks_passed.append(f"[C] Sprint Planning should have {expected_rate}% completion rate, found {stats.get('completion_rate', 0)}%")
        
            checks_passed.append(f"[C] Sprint Planning stats verified: {expected_total} items, {expected_rate}% completion")
    
        # Check 7: Verify divider exists
        divider_found = any(b.get("type") == "divider" for b in sorted_blocks)
        if not divider_found:
            errors.append("[X] Missing divider before dashboard generation date")
        else:
            checks_passed.append("[C] Divider present")
    
        # Check 8: Verify paragraph with italic 'Dashboard generated on [date]'
        found_generated_text = False
        for p in paragraph_blocks:
            content = p.get("content", "").lower()
            if "dashboard generated" in content:
                found_generated_text = True
                break
    
        if not found_generated_text:
            errors.append("[X] Missing italic paragraph 'Dashboard generated on [current date]'")
        else:
            checks_passed.append("[C] Dashboard generation date paragraph present")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: Bug Tracker Comprehensive Analysis
# =============================================================================
def _validate_bug_tracker_comprehensive_analysis(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Bug Tracker page with callout showing stats by section and fix rate section at end."""
    errors: list[str] = []

    checks_passed: list[str] = []
    try:
        import re

        bug_tracker = _find_page_by_title(final_state_backend, "Bug Tracker")
        if not bug_tracker:
            errors.append("[X] Bug Tracker page not found")
        else:
            checks_passed.append("[C] Bug Tracker page found")

        bug_tracker_id = bug_tracker.get("_id")
        bug_tracker_blocks = _get_blocks_for_page(final_state_backend, bug_tracker_id)
        sorted_blocks = sorted(bug_tracker_blocks, key=lambda b: b.get("order", 0))
        checks_passed.append("[C] Bug Tracker page found")

        # Find todos grouped by section
        sections = {"critical": [], "medium": [], "low": []}
        current_section = None

        for block in sorted_blocks:
            block_type = block.get("type", "")
            content = block.get("content", "").lower()
            if block_type in ["heading2", "heading_2"]:
                if "critical" in content:
                    current_section = "critical"
                elif "medium" in content:
                    current_section = "medium"
                elif "low" in content:
                    current_section = "low"
            elif block_type in ["todo", "to_do", "checkbox"] and current_section:
                is_checked = block.get("properties", {}).get("checked", False)
                sections[current_section].append({"checked": is_checked, "content": block.get("content", "")})

        # Check 1: Red callout with stats after main heading
        heading1_idx = None
        for i, block in enumerate(sorted_blocks):
            if block.get("type") in ["heading1", "heading_1"]:
                heading1_idx = i
                break

        if heading1_idx is None:
            errors.append("[X] Bug Tracker heading_1 not found")
        else:
            checks_passed.append("[C] Bug Tracker heading_1 found")

        red_callout_found = False
        for i in range(heading1_idx + 1, min(heading1_idx + 5, len(sorted_blocks))):
            block = sorted_blocks[i]
            if block.get("type") == "callout":
                properties = block.get("properties", {})
                bg_color = properties.get("backgroundColor", block.get("backgroundColor", ""))
                icon = properties.get("icon", block.get("icon", ""))
                content = block.get("content", "")
                has_red_bg = "red" in bg_color.lower() if bg_color else False
                has_alert_icon = "🚨" in icon if icon else False
                has_stats = "critical" in content.lower() and "medium" in content.lower() and "low" in content.lower()
                if has_red_bg and has_alert_icon and has_stats:
                    red_callout_found = True
                    checks_passed.append("[C] Red callout with stats found after heading")
                    break

        if not red_callout_found:
            errors.append("[X] Red callout with 🚨 icon and section stats not found after main heading")
        else:
            checks_passed.append("[C] Red callout with 🚨 icon and section stats found after main heading")

        # Check 2: New todo in Medium Priority section
        medium_section_start = None
        low_section_start = None
        for i, block in enumerate(sorted_blocks):
            block_type = block.get("type", "")
            content = block.get("content", "").lower()
            if block_type in ["heading2", "heading_2"]:
                if "medium" in content:
                    medium_section_start = i
                elif "low" in content:
                    low_section_start = i

        hover_todo_found = False
        if medium_section_start is not None and low_section_start is not None:
            for i in range(medium_section_start, low_section_start):
                block = sorted_blocks[i]
                if block.get("type") in ["todo", "to_do", "checkbox"]:
                    content = block.get("content", "")
                    if "button hover states" in content.lower() or "hover states" in content.lower():
                        is_unchecked = not block.get("properties", {}).get("checked", False)
                        if is_unchecked:
                            hover_todo_found = True
                            checks_passed.append("[C] New unchecked todo about button hover states found")
                            break

        if not hover_todo_found:
            errors.append("[X] New unchecked todo about 'button hover states' not found in Medium Priority section")
        else:
            checks_passed.append("[C] New unchecked todo about 'button hover states' found in Medium Priority section")

        # Check 3: Fix Rate by Priority section at end
        fix_rate_heading_found = False
        numbered_list_items = []
        for i, block in enumerate(sorted_blocks):
            block_type = block.get("type", "")
            content = block.get("content", "")
            if block_type in ["heading2", "heading_2"] and "fix rate" in content.lower() and "📊" in content:
                fix_rate_heading_found = True
            elif block_type in ["numberedList", "numbered_list", "numbered_list_item", "numbered"]:
                numbered_list_items.append(content)

        if not fix_rate_heading_found:
            errors.append("[X] heading_2 '📊 Fix Rate by Priority' not found at end of page")
        else:
            checks_passed.append("[C] Fix Rate by Priority heading_2 found")

        if len(numbered_list_items) < 3:
            errors.append(f"[X] Expected 3 numbered list items for fix rate, found {len(numbered_list_items)}")
        else:
            checks_passed.append(f"[C] Found 3 numbered list items for fix rate as expected")

        all_content = " ".join(numbered_list_items).lower()
        if not ("critical" in all_content and "medium" in all_content and "low" in all_content and "%" in all_content):
            errors.append("[X] Numbered list missing priority levels or percentages")
        else:
            checks_passed.append("[C] Numbered list has priority levels or percentages")

        # Verify sorted in descending order by percentage
        percentages_in_order = []
        for item in numbered_list_items:
            pct_match = re.search(r"(\d+(?:\.\d+)?)\s*%", item)
            if pct_match:
                percentages_in_order.append(float(pct_match.group(1)))

        if len(percentages_in_order) >= 3:
            is_sorted_desc = all(percentages_in_order[i] >= percentages_in_order[i + 1] for i in range(len(percentages_in_order) - 1))
            if not is_sorted_desc:
                errors.append(f"[X] Fix rate list should be sorted highest to lowest, found: {percentages_in_order}")
            else:
                checks_passed.append(f"[C] Numbered list correctly sorted by fix rate (descending)")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: Team Directory DevOps Section
# =============================================================================
def _validate_team_directory_devops(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Team Directory page with new DevOps Team section, image, and team callout."""
    errors: list[str] = []

    checks_passed = []

    try:
        team_directory = _find_page_by_title(final_state_backend, "Team Directory")
        if not team_directory:
            errors.append("[X] Team Directory page not found")
        else:
            checks_passed.append("[C] Team Directory page found")

        team_directory_id = team_directory.get("_id")
        directory_blocks = _get_blocks_for_page(final_state_backend, team_directory_id)
        sorted_blocks = sorted(directory_blocks, key=lambda b: b.get("order", 0))
        checks_passed.append("[C] Team Directory page found")

        # Check for DevOps Team heading with emoji between Engineering and Design
        engineering_idx = None
        devops_idx = None
        design_idx = None
        devops_has_emoji = False

        for i, block in enumerate(sorted_blocks):
            if block.get("type") in ["heading2", "heading_2"]:
                content = block.get("content", "")
                content_lower = content.lower()
                if "engineering" in content_lower and "team" in content_lower:
                    engineering_idx = i
                elif "devops" in content_lower and "team" in content_lower:
                    devops_idx = i
                    devops_has_emoji = "🔧" in content
                elif "design" in content_lower and "team" in content_lower:
                    design_idx = i

        if devops_idx is None:
            errors.append("[X] DevOps Team heading_2 not found")
        else:
            checks_passed.append("[C] DevOps Team heading_2 found")
        if not devops_has_emoji:
            errors.append("[X] DevOps Team heading_2 missing '🔧' emoji")
        else:
            checks_passed.append("[C] DevOps Team heading_2 has '🔧' emoji")

        if engineering_idx is not None and design_idx is not None:
            if not (engineering_idx < devops_idx < design_idx):
                errors.append(f"[X] DevOps Team not between Engineering and Design")
            else:
                checks_passed.append(f"[C] DevOps Team between Engineering and Design")

        checks_passed.append("[C] DevOps Team heading_2 with 🔧 emoji positioned correctly")

        # Check for team members as bulleted items
        devops_members = ["sarah kim", "michael chen", "lisa rodriguez"]
        found_members = []
        for block in sorted_blocks:
            if block.get("type") in ["bulletedList", "bulleted_list", "bulleted_list_item", "bulleted"]:
                content = block.get("content", "").lower()
                for member in devops_members:
                    if member in content and member not in found_members:
                        found_members.append(member)

        if len(found_members) < 3:
            errors.append(f"[X] Expected 3 DevOps team members, found {len(found_members)}")
        else:
            checks_passed.append("[C] All 3 DevOps team members found")

        # Check for image block
        image_blocks = [b for b in sorted_blocks if b.get("type") == "image"]
        if len(image_blocks) < 1:
            errors.append("[X] No image block found in Team Directory")
        else:
            checks_passed.append("[C] Image block found")

        # Check for blue callout with 👥 icon and team counts
        callout_found = False
        for block in sorted_blocks:
            if block.get("type") == "callout":
                properties = block.get("properties", {})
                bg_color = properties.get("backgroundColor", block.get("backgroundColor", ""))
                icon = properties.get("icon", block.get("icon", ""))
                content = block.get("content", "").lower()
                has_blue_bg = "blue" in bg_color.lower() if bg_color else False
                has_people_icon = "👥" in icon if icon else False
                has_team_count = "total team members" in content and "departments" in content
                if has_blue_bg and has_people_icon and has_team_count:
                    callout_found = True
                    checks_passed.append("[C] Blue callout with 👥 icon and team counts found")
                    break

        if not callout_found:
            errors.append("[X] Blue callout with 👥 icon and team member/department counts not found")
        else:
            checks_passed.append("[C] Blue callout with 👥 icon and team member/department counts found")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: Code Examples Repository Code Index
# =============================================================================
def _validate_code_examples_code_index(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Code Examples Repository with code index section."""
    errors: list[str] = []

    checks_passed = []

    try:
        code_examples = _find_page_by_title(final_state_backend, "Code Examples Repository")
        if not code_examples:
            errors.append("[X] Code Examples Repository page not found")
        else:
            checks_passed.append("[C] Code Examples Repository page found")

        page_id = code_examples.get("_id")
        page_blocks = _get_blocks_for_page(final_state_backend, page_id)
        sorted_blocks = sorted(page_blocks, key=lambda b: b.get("order", 0))
        checks_passed.append("[C] Code Examples Repository page found")

        # Check for Code Index heading_2 with emoji
        code_index_found = False
        for block in sorted_blocks:
            if block.get("type") in ["heading2", "heading_2"]:
                content = block.get("content", "")
                if "code index" in content.lower() and "🔧" in content:
                    code_index_found = True
                    break

        if not code_index_found:
            errors.append("[X] heading_2 '🔧 Code Index' not found")
        else:
            checks_passed.append("[C] Code Index heading_2 found")

        # Check for orange callout with 📊 icon
        callout_found = False
        for block in sorted_blocks:
            if block.get("type") == "callout":
                properties = block.get("properties", {})
                bg_color = properties.get("backgroundColor", block.get("backgroundColor", ""))
                icon = properties.get("icon", block.get("icon", ""))
                content = block.get("content", "").lower()
                has_orange_bg = "orange" in bg_color.lower() if bg_color else False
                has_chart_icon = "📊" in icon if icon else False
                has_count = "total code snippets" in content
                if has_orange_bg and has_chart_icon and has_count:
                    callout_found = True
                    checks_passed.append("[C] Orange callout with 📊 icon found")
                    break

        if not callout_found:
            errors.append("[X] Orange callout with 📊 icon and total code snippets count not found")
        else:
            checks_passed.append("[C] Orange callout with 📊 icon and total code snippets count found")

        # Check for bulleted list entries
        bulleted_items = [b for b in sorted_blocks if b.get("type") in ["bulletedList", "bulleted_list", "bulleted_list_item", "bulleted"]]
        if len(bulleted_items) < 1:
            errors.append("[X] No bulleted list entries for code index found")
        else:
            checks_passed.append(f"[C] Found {len(bulleted_items)} bulleted index entries")

        # Check for Language Distribution heading_3
        lang_dist_found = False
        for block in sorted_blocks:
            if block.get("type") in ["heading3", "heading_3"]:
                content = block.get("content", "")
                if "language distribution" in content.lower() and "🏷️" in content:
                    lang_dist_found = True
                    break

        if not lang_dist_found:
            errors.append("[X] heading_3 '🏷️ Language Distribution' not found")
        else:
            checks_passed.append("[C] Language Distribution heading_3 found")

        # Check for numbered list with language counts
        numbered_items = [b for b in sorted_blocks if b.get("type") in ["numberedList", "numbered_list", "numbered_list_item", "numbered"]]
        if len(numbered_items) < 1:
            errors.append("[X] No numbered list for language distribution found")
        else:
            checks_passed.append(f"[C] Found {len(numbered_items)} numbered list entries")

        # Check for divider
        if not any(b.get("type") == "divider" for b in sorted_blocks):
            errors.append("[X] Divider not found")
        else:
            checks_passed.append("[C] Divider found")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: Engineering Wiki Table of Contents
# =============================================================================
def _validate_engineering_wiki_table_of_contents(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Engineering Wiki with table of contents and statistics."""
    errors: list[str] = []

    checks_passed = []

    try:
        eng_wiki = _find_page_by_title(final_state_backend, "Engineering Wiki")
        if not eng_wiki:
            errors.append("[X] Engineering Wiki page not found")
        else:
            checks_passed.append("[C] Engineering Wiki page found")

        page_id = eng_wiki.get("_id")
        page_blocks = _get_blocks_for_page(final_state_backend, page_id)
        sorted_blocks = sorted(page_blocks, key=lambda b: b.get("order", 0))
        checks_passed.append("[C] Engineering Wiki page found")

        # Check for Table of Contents heading_2
        toc_found = False
        for block in sorted_blocks:
            if block.get("type") in ["heading2", "heading_2"]:
                content = block.get("content", "")
                if "table of contents" in content.lower() and "📑" in content:
                    toc_found = True
                    break

        if not toc_found:
            errors.append("[X] heading_2 '📑 Table of Contents' not found")
        else:
            checks_passed.append("[C] Table of Contents heading_2 found")

        # Check for numbered list (TOC entries)
        numbered_items = [b for b in sorted_blocks if b.get("type") in ["numberedList", "numbered_list", "numbered_list_item", "numbered"]]
        if len(numbered_items) < 1:
            errors.append("[X] No numbered list for TOC entries found")
        else:
            checks_passed.append(f"[C] Found {len(numbered_items)} numbered TOC entries")

        # Check for divider
        if not any(b.get("type") == "divider" for b in sorted_blocks):
            errors.append("[X] Divider after TOC not found")
        else:
            checks_passed.append("[C] Divider found")

        # Check for Document Statistics heading_3
        stats_found = False
        for block in sorted_blocks:
            if block.get("type") in ["heading3", "heading_3"]:
                content = block.get("content", "")
                if "document statistics" in content.lower() and "📊" in content:
                    stats_found = True
                    break

        if not stats_found:
            errors.append("[X] heading_3 '📊 Document Statistics' not found")
        else:
            checks_passed.append("[C] Document Statistics heading_3 found")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: External Resources Swap Sections
# =============================================================================
def _validate_external_resources_swap_sections(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate External Resources page with swapped sections and Quick Access callout."""
    errors: list[str] = []

    checks_passed = []

    try:
        ext_resources = _find_page_by_title(final_state_backend, "External Resources & Links")
        if not ext_resources:
            ext_resources = _find_page_by_title(final_state_backend, "External Resources")
        if not ext_resources:
            errors.append("[X] External Resources page not found")
        else:
            checks_passed.append("[C] External Resources page found")

        page_id = ext_resources.get("_id")
        page_blocks = _get_blocks_for_page(final_state_backend, page_id)
        sorted_blocks = sorted(page_blocks, key=lambda b: b.get("order", 0))
        checks_passed.append("[C] External Resources page found")

        # Find Documentation and Tools section positions
        doc_idx = None
        tools_idx = None
        for i, block in enumerate(sorted_blocks):
            if block.get("type") in ["heading2", "heading_2"]:
                content = block.get("content", "").lower()
                if "documentation" in content:
                    doc_idx = i
                elif "tools" in content:
                    tools_idx = i

        if doc_idx is None:
            errors.append("[X] Documentation section not found")
        else:
            checks_passed.append("[C] Documentation section found")
        if tools_idx is None:
            errors.append("[X] Tools section not found")
        else:
            checks_passed.append("[C] Tools section found")

        # Check if Tools appears before Documentation (swapped)
        if tools_idx > doc_idx:
            errors.append("[X] Tools section should appear before Documentation after swap")
        else:
            checks_passed.append("[C] Tools section now appears before Documentation (swapped)")

        # Check for Quick Access heading_2
        quick_access_found = False
        for block in sorted_blocks:
            if block.get("type") in ["heading2", "heading_2"]:
                content = block.get("content", "")
                if "quick access" in content.lower() and "🔗" in content:
                    quick_access_found = True
                    break

        if not quick_access_found:
            errors.append("[X] heading_2 '🔗 Quick Access' not found")
        else:
            checks_passed.append("[C] Quick Access heading_2 found")

        # Check for blue callout with pro tip
        callout_found = False
        for block in sorted_blocks:
            if block.get("type") == "callout":
                properties = block.get("properties", {})
                bg_color = properties.get("backgroundColor", block.get("backgroundColor", ""))
                content = block.get("content", "").lower()
                has_blue_bg = "blue" in bg_color.lower() if bg_color else False
                has_pro_tip = "pro tip" in content or "command" in content or "ctrl" in content
                if has_blue_bg and has_pro_tip:
                    callout_found = True
                    checks_passed.append("[C] Blue callout with pro tip found")
                    break

        if not callout_found:
            errors.append("[X] Blue callout with pro tip not found")
        else:
            checks_passed.append("[C] Blue callout with pro tip found")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: Team Retrospective Action Items
# =============================================================================
def _validate_team_retrospective_action_items(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Team Retrospective with action items section."""
    errors: list[str] = []

    checks_passed = []

    try:
        retro = _find_page_by_title(final_state_backend, "Team Retrospective")
        if not retro:
            errors.append("[X] Team Retrospective page not found")
        else:
            checks_passed.append("[C] Team Retrospective page found")

        page_id = retro.get("_id")
        page_blocks = _get_blocks_for_page(final_state_backend, page_id)
        sorted_blocks = sorted(page_blocks, key=lambda b: b.get("order", 0))
        checks_passed.append("[C] Team Retrospective page found")

        # Check for Action Items heading_2
        action_items_idx = None
        for i, block in enumerate(sorted_blocks):
            if block.get("type") in ["heading2", "heading_2"]:
                content = block.get("content", "").lower()
                if "action items" in content and "retrospective" in content:
                    action_items_idx = i
                    break

        if action_items_idx is None:
            errors.append("[X] heading_2 'Action Items from Retrospective' not found")
        else:
            checks_passed.append("[C] Action Items heading_2 found")

        # Check for Process Improvements and Team Initiatives headings
        process_found = False
        initiatives_found = False
        for block in sorted_blocks:
            if block.get("type") in ["heading3", "heading_3"]:
                content = block.get("content", "").lower()
                if "process improvements" in content:
                    process_found = True
                elif "team initiatives" in content:
                    initiatives_found = True

        if not process_found:
            errors.append("[X] heading_3 'Process Improvements' not found")
        else:
            checks_passed.append("[C] heading_3 'Process Improvements' found")
        if not initiatives_found:
            errors.append("[X] heading_3 'Team Initiatives' not found")
        else:
            checks_passed.append("[C] Both Process Improvements and Team Initiatives headings found")

        # Check for 6 todos (all unchecked)
        todo_blocks = [b for b in sorted_blocks if b.get("type") in ["todo", "to_do", "checkbox"]]
        action_todos = [t for t in todo_blocks if sorted_blocks.index(t) > action_items_idx]

        if len(action_todos) < 6:
            errors.append(f"[X] Expected at least 6 todo items, found {len(action_todos)}")
        else:
            checks_passed.append(f"[C] Found at least 6 todo items ({len(action_todos)})")

        # Verify all unchecked
        checked_todos = [t for t in action_todos if t.get("properties", {}).get("checked", False) or t.get("checked", False)]
        if len(checked_todos) > 0:
            errors.append(f"[X] All todos should be unchecked, but {len(checked_todos)} are checked")
        else:
            checks_passed.append("[C] All action item todos are unchecked")

        # Check for specific todos
        expected_todos = ["documentation templates", "code review checklist", "standups reminder", "knowledge sharing", "team building", "velocity dashboard"]
        all_todo_content = " ".join([t.get("content", "").lower() for t in action_todos])
        found_todos = sum(1 for expected in expected_todos if expected in all_todo_content)

        if found_todos < 4:
            errors.append(f"[X] Expected at least 4 specific todos, found {found_todos}")
        else:
            checks_passed.append(f"[C] Found {found_todos} of 6 expected todo items")

        # Check for divider
        if not any(b.get("type") == "divider" for b in sorted_blocks):
            errors.append("[X] Divider block not found")
        else:
            checks_passed.append("[C] Divider found")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: External Resources Hub Transformation
# =============================================================================
def _validate_external_resources_hub_transformation(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate External Resources transformation into comprehensive hub."""
    errors: list[str] = []

    checks_passed = []

    try:
        ext_resources = _find_page_by_title(final_state_backend, "External Resources & Links")
        if not ext_resources:
            ext_resources = _find_page_by_title(final_state_backend, "External Resources")
        if not ext_resources:
            errors.append("[X] External Resources page not found")
        else:
            checks_passed.append("[C] External Resources page found")

        page_id = ext_resources.get("_id")
        page_blocks = _get_blocks_for_page(final_state_backend, page_id)
        sorted_blocks = sorted(page_blocks, key=lambda b: b.get("order", 0))
        checks_passed.append("[C] External Resources page found")

        # Check for four required sections with emojis
        required_sections = {"learning resources": "📚", "development tools": "🛠️", "documentation": "📖", "partner links": "🤝"}
        found_sections = []

        for block in sorted_blocks:
            if block.get("type") in ["heading2", "heading_2"]:
                content = block.get("content", "")
                content_lower = content.lower()
                for section_name, emoji in required_sections.items():
                    if section_name in content_lower:
                        found_sections.append(section_name)
                        if emoji not in content:
                            errors.append(f"[X] Section '{section_name}' missing required emoji '{emoji}'")
                        else:
                            checks_passed.append(f"[C] Section '{section_name}' has required emoji '{emoji}'")

        missing_sections = [s for s in required_sections.keys() if s not in found_sections]
        if missing_sections:
            errors.append(f"[X] Missing sections: {', '.join(missing_sections)}")
        else:
            checks_passed.append("[C] All 4 required sections found with correct emojis")

        # Check for bookmarks with required URLs
        bookmark_blocks = [b for b in sorted_blocks if b.get("type") == "bookmark"]
        if len(bookmark_blocks) < 5:
            errors.append(f"[X] Expected at least 5 bookmarks, found {len(bookmark_blocks)}")
        else:
            checks_passed.append(f"[C] Found at least 5 bookmarks ({len(bookmark_blocks)})")

        required_urls = ["developers.notion.com", "react.dev", "typescriptlang.org", "aws.amazon.com", "github.com/donnemartin/system-design-primer"]
        found_urls = []
        bookmarks_with_captions = 0

        for bookmark in bookmark_blocks:
            url = bookmark.get("properties", {}).get("url", "") or bookmark.get("url", "") or bookmark.get("content", "")
            caption = bookmark.get("properties", {}).get("caption", "") or bookmark.get("caption", "")
            for req_url in required_urls:
                if req_url in url and req_url not in found_urls:
                    found_urls.append(req_url)
            if caption and len(caption.strip()) > 0:
                bookmarks_with_captions += 1

        if len(found_urls) < 3:
            errors.append(f"[X] Expected at least 3 of required bookmark URLs, found {len(found_urls)}")
        else:
            checks_passed.append(f"[C] Found {len(found_urls)}/5 required bookmark URLs")

        if bookmarks_with_captions < 3:
            errors.append(f"[X] Bookmarks should have captions, only {bookmarks_with_captions} have captions")
        else:
            checks_passed.append(f"[C] {bookmarks_with_captions} bookmarks have captions")

        # Check for dividers between sections
        dividers = [b for b in sorted_blocks if b.get("type") == "divider"]
        if len(dividers) < 2:
            errors.append(f"[X] Expected at least 2 dividers, found {len(dividers)}")
        else:
            checks_passed.append(f"[C] Found {len(dividers)} dividers")

        # Check for Blue/Green callouts with resource counts
        callout_blocks = [b for b in sorted_blocks if b.get("type") == "callout"]
        blue_green_callouts = 0
        for callout in callout_blocks:
            bg_color = callout.get("properties", {}).get("backgroundColor", callout.get("backgroundColor", ""))
            if bg_color:
                bg_lower = bg_color.lower()
                if "blue" in bg_lower or "green" in bg_lower:
                    content = callout.get("content", "").lower()
                    if "section contains" in content or "resources" in content:
                        blue_green_callouts += 1

        if blue_green_callouts < 2:
            errors.append(f"[X] Expected Blue/Green callouts with resource counts, found {blue_green_callouts}")
        else:
            checks_passed.append(f"[C] Found {blue_green_callouts} Blue/Green callouts")

        # Check for Resource Statistics section
        stats_found = False
        for block in sorted_blocks:
            if block.get("type") in ["heading2", "heading_2"]:
                content = block.get("content", "")
                if "resource statistics" in content.lower() and "📊" in content:
                    stats_found = True
                    break

        if not stats_found:
            errors.append("[X] heading_2 '📊 Resource Statistics' not found")
        else:
            checks_passed.append("[C] Resource Statistics section found")

        # Check for numbered list in statistics
        numbered_items = [b for b in sorted_blocks if b.get("type") in ["numberedList", "numbered_list", "numbered_list_item", "numbered"]]
        if len(numbered_items) < 2:
            errors.append(f"[X] Expected numbered list in statistics, found {len(numbered_items)} items")
        else:
            checks_passed.append(f"[C] Found {len(numbered_items)} numbered list items in statistics")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: External Resources Reorganization
# =============================================================================
def _validate_external_resources_reorganization(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate External Resources page with Curated Resources Hub heading, purple callout with bookmark count, section summaries before dividers, and Notion bookmark at end."""
    errors: list[str] = []

    checks_passed = []

    # Find External Resources & Links page
    try:
        ext_resources = _find_page_by_title(final_state_backend, "External Resources & Links")
        if not ext_resources:
            ext_resources = _find_page_by_title(final_state_backend, "External Resources")
        if not ext_resources:
            errors.append("[X] External Resources page not found")
        else:
            checks_passed.append("[C] External Resources page found")

        page_id = ext_resources.get("_id")
        page_blocks = _get_blocks_for_page(final_state_backend, page_id)
        sorted_blocks = sorted(page_blocks, key=lambda b: b.get("order", 0))
        checks_passed.append("[C] External Resources page found")

        # Count all bookmark blocks on the page
        bookmark_blocks = [b for b in sorted_blocks if b.get("type") == "bookmark"]
        total_bookmark_count = len(bookmark_blocks)
    
        # Check 1: Page starts with heading_1 '🔗 Curated Resources Hub'
        first_heading1 = None
        for block in sorted_blocks:
            if block.get("type") in ["heading1", "heading_1"]:
                first_heading1 = block
                break
    
        if not first_heading1:
            errors.append("[X] No heading_1 found on the page")
        else:
            checks_passed.append("[C] heading_1 found on the page")
    
        heading1_content = first_heading1.get("content", "")
        if "🔗" not in heading1_content or "curated resources hub" not in heading1_content.lower():
            errors.append(f"[X] First heading_1 should be '🔗 Curated Resources Hub', found: '{heading1_content}'")
        else:
            checks_passed.append("[C] Heading_1 '🔗 Curated Resources Hub' at the beginning")

        # Check 2: Purple callout with 📌 icon containing correct total bookmark count
        purple_callout_found = False
        for block in sorted_blocks:
            if block.get("type") == "callout":
                properties = block.get("properties", {})
                bg_color = properties.get("backgroundColor", block.get("backgroundColor", ""))
                icon = properties.get("icon", block.get("icon", ""))
                content = block.get("content", "")
            
                has_purple_bg = "purple" in bg_color.lower() if bg_color else False
                has_pin_icon = "📌" in icon if icon else False
            
                if has_purple_bg and has_pin_icon:
                    # Check content contains bookmark count
                    if "carefully selected external resources" in content.lower():
                        # Verify the count is present (we're flexible on exact number since new bookmark may be added)
                        purple_callout_found = True
                        checks_passed.append(f"[C] Purple callout with 📌 icon found with resource count")
                        break
    
        if not purple_callout_found:
            errors.append("[X] Purple callout with 📌 icon and resource count not found")
        else:
            checks_passed.append("[C] Purple callout with 📌 icon and resource count found")

        # Check 3: Find all dividers and verify Section Summary heading_3 before each
        divider_indices = []
        for i, block in enumerate(sorted_blocks):
            if block.get("type") == "divider":
                divider_indices.append(i)
    
        if len(divider_indices) == 0:
            errors.append("[X] No dividers found on the page")
        else:
            checks_passed.append("[C] dividers found on the page")
    
        section_summaries_found = 0
        for divider_idx in divider_indices:
            # Look for heading_3 '📑 Section Summary' before this divider
            for i in range(divider_idx - 1, max(0, divider_idx - 5), -1):
                block = sorted_blocks[i]
                if block.get("type") in ["heading3", "heading_3"]:
                    content = block.get("content", "")
                    if "📑" in content and "section summary" in content.lower():
                        section_summaries_found += 1
                        break
    
        if section_summaries_found < len(divider_indices):
            errors.append(f"[X] Expected Section Summary heading_3 before each divider, found {section_summaries_found} of {len(divider_indices)}")
        else:
            checks_passed.append(f"[C] Found {section_summaries_found} Section Summary headings before dividers")

        # Check 4: Verify paragraphs with section resource counts exist
        section_count_paragraphs = 0
        for block in sorted_blocks:
            if block.get("type") in ["paragraph", "text"]:
                content = block.get("content", "").lower()
                if "this section contains" in content and "resources" in content:
                    section_count_paragraphs += 1
    
        if section_count_paragraphs < len(divider_indices):
            errors.append(f"[X] Expected paragraphs with section counts, found {section_count_paragraphs}")
        else:
            checks_passed.append(f"[C] Found {section_count_paragraphs} section count paragraphs")

        # Check 5: New Notion bookmark at the end with URL 'https://notion.so'
        notion_bookmark_found = False
        for bookmark in bookmark_blocks:
            url = bookmark.get("properties", {}).get("url", "") or bookmark.get("url", "") or bookmark.get("content", "")
            caption = bookmark.get("properties", {}).get("caption", "") or bookmark.get("caption", "")
            if "notion.so" in url.lower():
                if "official notion documentation" in caption.lower() or "notion documentation" in caption.lower():
                    notion_bookmark_found = True
                    break
                # Also accept if just the URL is correct
                notion_bookmark_found = True
                break
    
        if not notion_bookmark_found:
            errors.append("[X] Notion bookmark (https://notion.so) with caption 'Official Notion Documentation' not found")
        else:
            checks_passed.append("[C] Notion bookmark at the end with correct URL and caption")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: Feature Requests Priority Reorganization
# =============================================================================
def _validate_feature_requests_priority_reorganization(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Feature Requests page with Priority Matrix, reorganized todos by checked status, and Backlog section."""
    errors: list[str] = []

    checks_passed = []

    # Find Feature Requests page
    try:
        feature_requests = _find_page_by_title(final_state_backend, "Feature Requests")
        if not feature_requests:
            errors.append("[X] Feature Requests page not found")
        else:
            checks_passed.append("[C] Feature Requests page found")

        page_id = feature_requests.get("_id")
        page_blocks = _get_blocks_for_page(final_state_backend, page_id)
        sorted_blocks = sorted(page_blocks, key=lambda b: b.get("order", 0))
        checks_passed.append("[C] Feature Requests page found")

        # Check 1: heading_2 '🚨 Priority Matrix' exists immediately after title (first heading)
        priority_matrix_idx = None
        for i, block in enumerate(sorted_blocks):
            if block.get("type") in ["heading2", "heading_2"]:
                content = block.get("content", "")
                if "🚨" in content and "priority matrix" in content.lower():
                    priority_matrix_idx = i
                    break
    
        if priority_matrix_idx is None:
            errors.append("[X] heading_2 '🚨 Priority Matrix' not found")
        else:
            checks_passed.append("[C] Priority Matrix heading_2 found")

        # Check 2: Three heading_3 sections under Priority Matrix
        high_priority_idx = None
        medium_priority_idx = None
        backlog_idx = None
    
        for i, block in enumerate(sorted_blocks):
            if block.get("type") in ["heading3", "heading_3"]:
                content = block.get("content", "")
                if "🔴" in content and "high priority" in content.lower():
                    high_priority_idx = i
                elif "🟡" in content and "medium priority" in content.lower():
                    medium_priority_idx = i
                elif "🟢" in content and "backlog" in content.lower():
                    backlog_idx = i
    
        if high_priority_idx is None:
            errors.append("[X] heading_3 '🔴 High Priority (Checked Items)' not found")
        else:
            checks_passed.append("[C] heading_3 '🔴 High Priority (Checked Items)' found")
        if medium_priority_idx is None:
            errors.append("[X] heading_3 '🟡 Medium Priority (Unchecked Items)' not found")
        else:
            checks_passed.append("[C] heading_3 '🟡 Medium Priority (Unchecked Items)' found")
        if backlog_idx is None:
            errors.append("[X] heading_3 '🟢 Backlog' not found")
        else:
            checks_passed.append("[C] All three priority section headings found")

        # Check 3: Backlog has paragraph 'Items for future consideration:'
        backlog_paragraph_found = False
        for i in range(backlog_idx + 1, min(backlog_idx + 10, len(sorted_blocks))):
            block = sorted_blocks[i]
            if block.get("type") in ["paragraph", "text"]:
                content = block.get("content", "").lower()
                if "items for future consideration" in content:
                    backlog_paragraph_found = True
                    break
    
        if not backlog_paragraph_found:
            errors.append("[X] Backlog paragraph 'Items for future consideration:' not found")
        else:
            checks_passed.append("[C] Backlog paragraph found")

        # Check 4: Backlog section has three specific new todos
        expected_backlog_todos = [
            "cloud sync functionality",
            "two-factor authentication",
            "mobile app development"
        ]
    
        # Find todos in Backlog section
        backlog_todos = []
        for i in range(backlog_idx + 1, len(sorted_blocks)):
            block = sorted_blocks[i]
            if block.get("type") in ["heading2", "heading_2", "heading3", "heading_3"]:
                # Hit next section
                break
            if block.get("type") in ["todo", "to_do", "checkbox"]:
                backlog_todos.append(block.get("content", "").lower())
    
        found_backlog_todos = 0
        for expected in expected_backlog_todos:
            for todo_content in backlog_todos:
                if expected in todo_content:
                    found_backlog_todos += 1
                    break
    
        if found_backlog_todos < 3:
            errors.append(f"[X] Expected 3 specific backlog todos, found {found_backlog_todos}")
        else:
            checks_passed.append("[C] All 3 backlog todos found (cloud sync, two-factor auth, mobile app)")

        # Check 5: Verify Priority Matrix appears early (after title but before original content)
        if priority_matrix_idx > 5:
            errors.append(f"[X] Priority Matrix should appear early on page, but found at position {priority_matrix_idx}")
        else:
            checks_passed.append("[C] Priority Matrix positioned correctly after title")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: API Documentation Restructuring
# =============================================================================
def _validate_api_documentation_restructuring(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate API Documentation page with API Reference Guide heading, Quick Navigation, code block, callout, and image."""
    errors: list[str] = []

    checks_passed = []

    # Find API Documentation page
    try:
        api_docs = _find_page_by_title(final_state_backend, "API Documentation")
        if not api_docs:
            errors.append("[X] API Documentation page not found")
        else:
            checks_passed.append("[C] API Documentation page found")

        page_id = api_docs.get("_id")
        page_blocks = _get_blocks_for_page(final_state_backend, page_id)
        sorted_blocks = sorted(page_blocks, key=lambda b: b.get("order", 0))
        checks_passed.append("[C] API Documentation page found")

        # Check 1: heading_1 '📚 API Reference Guide' at the very top
        first_heading1 = None
        for block in sorted_blocks:
            if block.get("type") in ["heading1", "heading_1"]:
                first_heading1 = block
                break
    
        if not first_heading1:
            errors.append("[X] No heading_1 found on the page")
        else:
            checks_passed.append("[C] heading_1 found on the page")
    
        heading1_content = first_heading1.get("content", "")
        if "📚" not in heading1_content or "api reference guide" not in heading1_content.lower():
            errors.append(f"[X] First heading_1 should be '📚 API Reference Guide', found: '{heading1_content}'")
        else:
            checks_passed.append("[C] Heading_1 '📚 API Reference Guide' at the top")

        # Check 2: heading_2 '🔍 Quick Navigation' with numbered list
        quick_nav_idx = None
        for i, block in enumerate(sorted_blocks):
            if block.get("type") in ["heading2", "heading_2"]:
                content = block.get("content", "")
                if "🔍" in content and "quick navigation" in content.lower():
                    quick_nav_idx = i
                    break
    
        if quick_nav_idx is None:
            errors.append("[X] heading_2 '🔍 Quick Navigation' not found")
        else:
            checks_passed.append("[C] Quick Navigation heading_2 found")

        # Check 3: Numbered list with 5 items
        expected_nav_items = [
            "authentication & security",
            "core endpoints",
            "rate limiting",
            "error handling",
            "sdk downloads"
        ]
    
        numbered_items = []
        for i in range(quick_nav_idx + 1, min(quick_nav_idx + 15, len(sorted_blocks))):
            block = sorted_blocks[i]
            if block.get("type") in ["heading2", "heading_2", "divider"]:
                break
            if block.get("type") in ["numberedList", "numbered_list", "numbered_list_item", "numbered"]:
                numbered_items.append(block.get("content", "").lower())
    
        found_items = sum(1 for expected in expected_nav_items if any(expected in item for item in numbered_items))
        if found_items < 5:
            errors.append(f"[X] Expected 5 navigation items, found {found_items}")
        else:
            checks_passed.append("[C] All 5 navigation items found in numbered list")

        # Check 4: Divider after navigation section
        divider_found = False
        for i in range(quick_nav_idx + 1, len(sorted_blocks)):
            if sorted_blocks[i].get("type") == "divider":
                divider_found = True
                break
            if sorted_blocks[i].get("type") in ["heading2", "heading_2"]:
                # Check if this is Getting Started
                content = sorted_blocks[i].get("content", "")
                if "getting started" in content.lower():
                    break
    
        if not divider_found:
            errors.append("[X] Divider between navigation and Getting Started not found")
        else:
            checks_passed.append("[C] Divider found between sections")

        # Check 5: heading_2 '⚡ Getting Started'
        getting_started_idx = None
        for i, block in enumerate(sorted_blocks):
            if block.get("type") in ["heading2", "heading_2"]:
                content = block.get("content", "")
                if "⚡" in content and "getting started" in content.lower():
                    getting_started_idx = i
                    break
    
        if getting_started_idx is None:
            errors.append("[X] heading_2 '⚡ Getting Started' not found")
        else:
            checks_passed.append("[C] Getting Started heading_2 found")

        # Check 6: Code block with curl command and bash language
        code_block_found = False
        for block in sorted_blocks:
            if block.get("type") == "code":
                content = block.get("content", "")
                properties = block.get("properties", {})
                language = properties.get("language", block.get("language", ""))
            
                if "curl" in content and "api.acme-corp.com" in content:
                    if "bash" in language.lower() if language else True:
                        code_block_found = True
                        checks_passed.append("[C] Bash code block with curl command found")
                        break
    
        if not code_block_found:
            errors.append("[X] Code block with curl command (bash) not found")
        else:
            checks_passed.append("[C] Code block with curl command (bash) found")

        # Check 7: Blue callout with 💡 icon and API explorer tip
        blue_callout_found = False
        for block in sorted_blocks:
            if block.get("type") == "callout":
                properties = block.get("properties", {})
                bg_color = properties.get("backgroundColor", block.get("backgroundColor", ""))
                icon = properties.get("icon", block.get("icon", ""))
                content = block.get("content", "")
            
                has_blue_bg = "blue" in bg_color.lower() if bg_color else False
                has_bulb_icon = "💡" in icon if icon else False
                has_explorer_text = "api explorer" in content.lower() or "pro tip" in content.lower()
            
                if has_blue_bg and (has_bulb_icon or has_explorer_text):
                    blue_callout_found = True
                    checks_passed.append("[C] Blue callout with API explorer tip found")
                    break
    
        if not blue_callout_found:
            errors.append("[X] Blue callout with 💡 icon and API explorer tip not found")
        else:
            checks_passed.append("[C] Blue callout with 💡 icon and API explorer tip found")

        # Check 8: Image at the end with caption 'API Architecture Overview'
        image_found = False
        for block in sorted_blocks:
            if block.get("type") == "image":
                caption = block.get("properties", {}).get("caption", "") or block.get("caption", "")
                url = block.get("properties", {}).get("url", "") or block.get("url", "") or block.get("content", "")
            
                if "api architecture overview" in caption.lower() or "img_3" in url.lower():
                    image_found = True
                    checks_passed.append("[C] Architecture image with caption found")
                    break
    
        if not image_found:
            errors.append("[X] Image with caption 'API Architecture Overview' not found")
        else:
            checks_passed.append("[C] Image with caption 'API Architecture Overview' found")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: Company Handbook Swap Values and Benefits
# =============================================================================
def _validate_company_handbook_swap_values_benefits(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Company Handbook with swapped Our Values and Benefits sections, and new International Team Guidelines."""
    errors: list[str] = []

    checks_passed = []

    # Find Company Handbook page
    try:
        handbook = _find_page_by_title(final_state_backend, "Company Handbook")
        if not handbook:
            errors.append("[X] Company Handbook page not found")
        else:
            checks_passed.append("[C] Company Handbook page found")

        page_id = handbook.get("_id")
        page_blocks = _get_blocks_for_page(final_state_backend, page_id)
        sorted_blocks = sorted(page_blocks, key=lambda b: b.get("order", 0))
        checks_passed.append("[C] Company Handbook page found")

        # Find indices of key sections
        our_values_idx = None
        benefits_idx = None
        work_policies_idx = None
        time_off_idx = None
        international_guidelines_idx = None

        for i, block in enumerate(sorted_blocks):
            content_lower = block.get("content", "").lower()
            block_type = block.get("type", "")
        
            if block_type in ["heading2", "heading_2"]:
                if "our values" in content_lower:
                    our_values_idx = i
                elif "benefits" in content_lower:
                    benefits_idx = i
                elif "work policies" in content_lower:
                    work_policies_idx = i
            elif block_type in ["heading3", "heading_3"]:
                if "time off" in content_lower:
                    time_off_idx = i
                elif "international team guidelines" in content_lower and "🌍" in block.get("content", ""):
                    international_guidelines_idx = i

        if our_values_idx is None:
            errors.append("[X] Our Values section heading not found")
        else:
            checks_passed.append("[C] Our Values section heading found")
        if benefits_idx is None:
            errors.append("[X] Benefits section heading not found")
        else:
            checks_passed.append("[C] Benefits section heading found")
        if work_policies_idx is None:
            errors.append("[X] Work Policies section heading not found")
        else:
            checks_passed.append("[C] All main section headings found")

        # Check 1: Benefits now appears where Our Values was (Benefits should come before Work Policies)
        # Original order: Our Values -> Work Policies -> Benefits
        # Swapped order: Benefits -> Work Policies -> Our Values
        if benefits_idx >= work_policies_idx:
            errors.append(f"[X] Benefits section (position {benefits_idx}) should appear before Work Policies (position {work_policies_idx}) after swap")
        else:
            checks_passed.append("[C] Benefits section now appears before Work Policies (swapped)")

        # Check 2: Our Values now appears after Work Policies (where Benefits originally was)
        if our_values_idx <= work_policies_idx:
            errors.append(f"[X] Our Values section (position {our_values_idx}) should appear after Work Policies (position {work_policies_idx}) after swap")
        else:
            checks_passed.append("[C] Our Values section now appears after Work Policies (swapped)")

        # Check 3: Benefits section has numbered list items (preserving content)
        benefits_numbered_count = 0
        for i in range(benefits_idx + 1, len(sorted_blocks)):
            block = sorted_blocks[i]
            if block.get("type") in ["heading2", "heading_2"]:
                break
            if block.get("type") in ["numberedList", "numbered_list", "numbered_list_item", "numbered"]:
                benefits_numbered_count += 1
    
        if benefits_numbered_count < 4:
            errors.append(f"[X] Benefits section should have numbered list items, found {benefits_numbered_count}")
        else:
            checks_passed.append(f"[C] Benefits section preserved with {benefits_numbered_count} numbered list items")

        # Check 4: Our Values section has bulleted list items (preserving content)
        our_values_bulleted_count = 0
        for i in range(our_values_idx + 1, len(sorted_blocks)):
            block = sorted_blocks[i]
            if block.get("type") in ["heading2", "heading_2"]:
                break
            if block.get("type") in ["bulletedList", "bulleted_list", "bulleted_list_item", "bulleted"]:
                our_values_bulleted_count += 1
    
        if our_values_bulleted_count < 3:
            errors.append(f"[X] Our Values section should have bulleted list items, found {our_values_bulleted_count}")
        else:
            checks_passed.append(f"[C] Our Values section preserved with {our_values_bulleted_count} bulleted list items")

        # Check 5: International Team Guidelines heading_3 exists
        if international_guidelines_idx is None:
            errors.append("[X] heading_3 '🌍 International Team Guidelines' not found")
        else:
            checks_passed.append("[C] International Team Guidelines heading_3 found")

        # Check 6: International Team Guidelines is positioned correctly (after Time Off, before Our Values/end of Work Policies section)
        if time_off_idx is not None:
            if international_guidelines_idx <= time_off_idx:
                errors.append(f"[X] International Team Guidelines (position {international_guidelines_idx}) should appear after Time Off (position {time_off_idx})")
            else:
                checks_passed.append("[C] International Team Guidelines positioned correctly in Work Policies section")

        # Check 7: Yellow callout with 🌐 icon under International Team Guidelines
        yellow_callout_found = False
        for i in range(international_guidelines_idx + 1, min(international_guidelines_idx + 5, len(sorted_blocks))):
            block = sorted_blocks[i]
            if block.get("type") == "callout":
                properties = block.get("properties", {})
                bg_color = properties.get("backgroundColor", block.get("backgroundColor", ""))
                icon = properties.get("icon", block.get("icon", ""))
                content = block.get("content", "")
            
                has_yellow_bg = "yellow" in bg_color.lower() if bg_color else False
                has_globe_icon = "🌐" in icon if icon else False
                has_correct_text = "time zones" in content.lower() or "utc" in content.lower()
            
                if has_yellow_bg and has_globe_icon and has_correct_text:
                    yellow_callout_found = True
                    break
    
        if not yellow_callout_found:
            errors.append("[X] Yellow callout with 🌐 icon and time zone text not found under International Team Guidelines")
        else:
            checks_passed.append("[C] Yellow callout with correct icon and text found")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: Project Documentation Multi-Level Analysis
# =============================================================================
def _validate_project_documentation_multilevel_analysis(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Documentation Health Check page as child of Project Documentation with multi-level todo analysis."""
    errors: list[str] = []

    checks_passed = []

    # Find Project Documentation page
    try:
        project_docs = _find_page_by_title(final_state_backend, "Project Documentation")
        if not project_docs:
            errors.append("[X] Project Documentation page not found")
        else:
            checks_passed.append("[C] Project Documentation page found")
    
        project_docs_id = project_docs.get("_id")
        checks_passed.append("[C] Project Documentation page found")

        # Find Documentation Health Check as child of Project Documentation
        health_check = None
        child_pages = _get_child_pages(final_state_backend, project_docs_id)
        for child in child_pages:
            title = child.get("title", "").lower()
            if "documentation health check" in title:
                health_check = child
                break
    
        if not health_check:
            errors.append("[X] Documentation Health Check page not found as child of Project Documentation")
        else:
            checks_passed.append("[C] Documentation Health Check page found as child of Project Documentation")
    
        # Check it's actually a child of Project Documentation
        if health_check.get("parentId") != project_docs_id:
            errors.append("[X] Documentation Health Check is not a child of Project Documentation")
        else:
            checks_passed.append("[C] Documentation Health Check is a child of Project Documentation")

        # Check 1: Page has 🏥 icon
        icon = health_check.get("icon", "")
        if "🏥" not in icon:
            errors.append(f"[X] Documentation Health Check should have 🏥 icon, found: '{icon}'")
        else:
            checks_passed.append("[C] Documentation Health Check has 🏥 icon")

        health_check_id = health_check.get("_id")
        health_check_blocks = _get_blocks_for_page(final_state_backend, health_check_id)
        sorted_blocks = sorted(health_check_blocks, key=lambda b: b.get("order", 0))

        # Check 2: heading_1 with title
        found_main_heading = any(
            b.get("type") in ["heading1", "heading_1"] and
            "documentation health check" in b.get("content", "").lower()
            for b in sorted_blocks
        )
        if not found_main_heading:
            errors.append("[X] heading_1 'Documentation Health Check' not found")
        else:
            checks_passed.append("[C] Main heading_1 present")

        # Check 3: heading_2 '📊 Task Completion Metrics'
        metrics_heading_found = any(
            b.get("type") in ["heading2", "heading_2"] and
            "📊" in b.get("content", "") and
            "task completion metrics" in b.get("content", "").lower()
            for b in sorted_blocks
        )
        if not metrics_heading_found:
            errors.append("[X] heading_2 '📊 Task Completion Metrics' not found")
        else:
            checks_passed.append("[C] Task Completion Metrics heading_2 present")

        # Check 4: Bulleted list items with page paths and stats
        bulleted_items = [
            b for b in sorted_blocks
            if b.get("type") in ["bulletedList", "bulleted_list", "bulleted_list_item", "bulleted"]
        ]
    
        if len(bulleted_items) < 2:
            errors.append(f"[X] Expected bulleted list items with page paths, found {len(bulleted_items)}")
        else:
            checks_passed.append(f"[C] Expected bulleted list items with page paths, found {len(bulleted_items)}")
    
        # Verify at least some items have the expected format with paths
        path_items_found = 0
        for item in bulleted_items:
            content = item.get("content", "")
            # Check for hierarchical path format (e.g., "Architecture > Frontend")
            if ">" in content or ("/" in content and ("tasks" in content.lower() or "complete" in content.lower())):
                path_items_found += 1
            # Also accept format with just stats
            elif "tasks" in content.lower() or "complete" in content.lower() or "%" in content:
                path_items_found += 1
    
        if path_items_found < 2:
            errors.append(f"[X] Expected bulleted items with page paths and stats, found {path_items_found}")
        else:
            checks_passed.append(f"[C] Found {path_items_found} bulleted items with page paths and completion stats")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: External Resources Bookmarks and Callout
# =============================================================================
def _validate_external_resources_bookmarks_callout(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate External Resources page with green callout after Documentation heading and Learning Platforms section with bookmarks."""
    errors: list[str] = []

    checks_passed = []

    # Find External Resources & Links page
    try:
        ext_resources = _find_page_by_title(final_state_backend, "External Resources & Links")
        if not ext_resources:
            ext_resources = _find_page_by_title(final_state_backend, "External Resources")
        if not ext_resources:
            errors.append("[X] External Resources page not found")
        else:
            checks_passed.append("[C] External Resources page found")

        page_id = ext_resources.get("_id")
        page_blocks = _get_blocks_for_page(final_state_backend, page_id)
        sorted_blocks = sorted(page_blocks, key=lambda b: b.get("order", 0))
        checks_passed.append("[C] External Resources page found")

        # Find Documentation heading
        documentation_idx = None
        for i, block in enumerate(sorted_blocks):
            if block.get("type") in ["heading2", "heading_2"]:
                content = block.get("content", "").lower()
                if "documentation" in content:
                    documentation_idx = i
                    break
    
        if documentation_idx is None:
            errors.append("[X] Documentation heading not found")
        else:
            checks_passed.append("[C] Documentation heading found")

        # Check 1: Green callout with 📊 icon after Documentation heading
        green_callout_found = False
        green_callout_idx = None
        for i in range(documentation_idx + 1, min(documentation_idx + 10, len(sorted_blocks))):
            block = sorted_blocks[i]
            if block.get("type") in ["heading2", "heading_2", "divider"]:
                break  # Hit next section
            if block.get("type") == "callout":
                properties = block.get("properties", {})
                bg_color = properties.get("backgroundColor", block.get("backgroundColor", ""))
                icon = properties.get("icon", block.get("icon", ""))
                content = block.get("content", "")
            
                has_green_bg = "green" in bg_color.lower() if bg_color else False
                has_chart_icon = "📊" in icon if icon else False
                has_correct_text = "essential documentation links" in content.lower() or "section contains" in content.lower()
            
                if has_green_bg and (has_chart_icon or has_correct_text):
                    green_callout_found = True
                    green_callout_idx = i
                    break
    
        if not green_callout_found:
            errors.append("[X] Green callout with 📊 icon after Documentation heading not found")
        else:
            checks_passed.append("[C] Green callout with bookmark count found after Documentation heading")

        # Find divider
        divider_idx = None
        for i, block in enumerate(sorted_blocks):
            if block.get("type") == "divider":
                divider_idx = i
                break
    
        if divider_idx is None:
            errors.append("[X] Divider between sections not found")
        else:
            checks_passed.append("[C] Divider found")

        # Check 2: heading_2 '🎓 Learning Platforms' after divider
        learning_platforms_idx = None
        for i in range(divider_idx + 1, len(sorted_blocks)):
            block = sorted_blocks[i]
            if block.get("type") in ["heading2", "heading_2"]:
                content = block.get("content", "")
                if "🎓" in content and "learning platforms" in content.lower():
                    learning_platforms_idx = i
                    break
    
        if learning_platforms_idx is None:
            errors.append("[X] heading_2 '🎓 Learning Platforms' not found after divider")
        else:
            checks_passed.append("[C] Learning Platforms heading_2 found after divider")

        # Check 3: Three bookmark blocks with specific URLs and captions
        expected_bookmarks = {
            "coursera.org": "online courses",
            "udemy.com": "video tutorials",
            "pluralsight.com": "tech skills platform"
        }
    
        learning_bookmarks = []
        for i in range(learning_platforms_idx + 1, len(sorted_blocks)):
            block = sorted_blocks[i]
            if block.get("type") in ["heading2", "heading_2"]:
                break
            if block.get("type") == "bookmark":
                url = block.get("properties", {}).get("url", "") or block.get("url", "") or block.get("content", "")
                caption = block.get("properties", {}).get("caption", "") or block.get("caption", "")
                learning_bookmarks.append({"url": url.lower(), "caption": caption.lower()})
    
        found_bookmarks = 0
        for expected_url, expected_caption in expected_bookmarks.items():
            for bookmark in learning_bookmarks:
                if expected_url in bookmark["url"]:
                    found_bookmarks += 1
                    break
    
        if found_bookmarks < 3:
            errors.append(f"[X] Expected 3 Learning Platform bookmarks (Coursera, Udemy, Pluralsight), found {found_bookmarks}")
        else:
            checks_passed.append("[C] All 3 Learning Platform bookmarks found with correct URLs")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: Q4 2024 Planning Summary
# =============================================================================
def _validate_q4_planning_summary(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Q4 2024 Planning Summary page as child of Project Roadmap with Q1/Q2 analysis and carryover tasks."""
    errors: list[str] = []

    checks_passed = []

    # Find Project Roadmap page
    try:
        roadmap = _find_page_by_title(final_state_backend, "Project Roadmap")
        if not roadmap:
            errors.append("[X] Project Roadmap page not found")
        else:
            checks_passed.append("[C] Project Roadmap page found")
    
        roadmap_id = roadmap.get("_id")
        checks_passed.append("[C] Project Roadmap page found")

        # Find Q4 2024 Planning Summary as child of Project Roadmap
        q4_planning = None
        child_pages = _get_child_pages(final_state_backend, roadmap_id)
        for child in child_pages:
            title = child.get("title", "").lower()
            if "q4" in title and "planning" in title:
                q4_planning = child
                break
    
        if not q4_planning:
            errors.append("[X] Q4 2024 Planning Summary page not found as child of Project Roadmap")
        else:
            checks_passed.append("[C] Q4 2024 Planning Summary page found as child of Project Roadmap")
    
        if q4_planning.get("parentId") != roadmap_id:
            errors.append("[X] Q4 2024 Planning Summary is not a child of Project Roadmap")
        else:
            checks_passed.append("[C] Q4 2024 Planning Summary is a child of Project Roadmap")

        q4_id = q4_planning.get("_id")
        q4_blocks = _get_blocks_for_page(final_state_backend, q4_id)
        sorted_blocks = sorted(q4_blocks, key=lambda b: b.get("order", 0))

        # Check 1: heading_1 '📅 Q4 2024 Planning Summary'
        found_main_heading = any(
            b.get("type") in ["heading1", "heading_1"] and
            "📅" in b.get("content", "") and
            "q4" in b.get("content", "").lower() and
            "planning" in b.get("content", "").lower()
            for b in sorted_blocks
        )
        if not found_main_heading:
            errors.append("[X] heading_1 '📅 Q4 2024 Planning Summary' not found")
        else:
            checks_passed.append("[C] Main heading_1 present")

        # Check 2: heading_2 '🔄 Previous Quarters Analysis'
        prev_quarters_found = any(
            b.get("type") in ["heading2", "heading_2"] and
            "🔄" in b.get("content", "") and
            "previous quarters" in b.get("content", "").lower()
            for b in sorted_blocks
        )
        if not prev_quarters_found:
            errors.append("[X] heading_2 '🔄 Previous Quarters Analysis' not found")
        else:
            checks_passed.append("[C] Previous Quarters Analysis heading_2 present")

        # Check 3: Numbered list with Q1 and Q2 completion rates
        numbered_items = [
            b for b in sorted_blocks
            if b.get("type") in ["numberedList", "numbered_list", "numbered_list_item", "numbered"]
        ]
    
        q1_rate_found = False
        q2_rate_found = False
        for item in numbered_items:
            content = item.get("content", "").lower()
            if "q1" in content and "completion" in content:
                q1_rate_found = True
            if "q2" in content and "completion" in content:
                q2_rate_found = True
    
        if not q1_rate_found or not q2_rate_found:
            errors.append(f"[X] Expected Q1 and Q2 completion rates in numbered list, found Q1={q1_rate_found}, Q2={q2_rate_found}")
        else:
            checks_passed.append("[C] Q1 and Q2 completion rates in numbered list")

        # Check 4: heading_2 '🎯 Q4 Objectives'
        q4_objectives_found = any(
            b.get("type") in ["heading2", "heading_2"] and
            "🎯" in b.get("content", "") and
            "q4 objectives" in b.get("content", "").lower()
            for b in sorted_blocks
        )
        if not q4_objectives_found:
            errors.append("[X] heading_2 '🎯 Q4 Objectives' not found")
        else:
            checks_passed.append("[C] Q4 Objectives heading_2 present")

        # Check 5: Yellow callout with ⚡ icon
        yellow_callout_found = False
        for block in sorted_blocks:
            if block.get("type") == "callout":
                properties = block.get("properties", {})
                bg_color = properties.get("backgroundColor", block.get("backgroundColor", ""))
                icon = properties.get("icon", block.get("icon", ""))
                content = block.get("content", "")
            
                has_yellow_bg = "yellow" in bg_color.lower() if bg_color else False
                has_lightning_icon = "⚡" in icon if icon else False
                has_performance_text = "q1-q2 performance" in content.lower() or "focus areas" in content.lower()
            
                if has_yellow_bg and (has_lightning_icon or has_performance_text):
                    yellow_callout_found = True
                    break
    
        if not yellow_callout_found:
            errors.append("[X] Yellow callout with ⚡ icon not found")
        else:
            checks_passed.append("[C] Yellow callout with ⚡ icon present")

        # Check 6: heading_3 '📊 Carryover Tasks'
        carryover_found = any(
            b.get("type") in ["heading3", "heading_3"] and
            "📊" in b.get("content", "") and
            "carryover tasks" in b.get("content", "").lower()
            for b in sorted_blocks
        )
        if not carryover_found:
            errors.append("[X] heading_3 '📊 Carryover Tasks' not found")
        else:
            checks_passed.append("[C] Carryover Tasks heading_3 present")

        # Check 7: Bulleted list with carryover items
        bulleted_items = [
            b for b in sorted_blocks
            if b.get("type") in ["bulletedList", "bulleted_list", "bulleted_list_item", "bulleted"]
        ]
    
        if len(bulleted_items) < 1:
            errors.append("[X] Expected bulleted list items for carryover tasks")
        else:
            checks_passed.append(f"[C] Found {len(bulleted_items)} carryover task items")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: Design System Component Inventory
# =============================================================================
def _validate_design_system_component_inventory(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Design System page with Component Audit section after Typography, including counts and usage guidelines."""
    errors: list[str] = []

    checks_passed = []

    # Find Design System page
    try:
        design_system = _find_page_by_title(final_state_backend, "Design System")
        if not design_system:
            errors.append("[X] Design System page not found")
        else:
            checks_passed.append("[C] Design System page found")

        page_id = design_system.get("_id")
        page_blocks = _get_blocks_for_page(final_state_backend, page_id)
        sorted_blocks = sorted(page_blocks, key=lambda b: b.get("order", 0))
        checks_passed.append("[C] Design System page found")

        # Find Typography heading_2 index
        typography_idx = None
        for i, block in enumerate(sorted_blocks):
            if block.get("type") in ["heading2", "heading_2"]:
                content = block.get("content", "").lower()
                if "typography" in content:
                    typography_idx = i
                    break
    
        if typography_idx is None:
            errors.append("[X] Typography heading_2 not found")
        else:
            checks_passed.append("[C] Typography heading_2 found")

        # Check 1: heading_2 '🧩 Component Audit' exists
        component_audit_idx = None
        for i, block in enumerate(sorted_blocks):
            if block.get("type") in ["heading2", "heading_2"]:
                content = block.get("content", "")
                if "🧩" in content and "component audit" in content.lower():
                    component_audit_idx = i
                    break
    
        if component_audit_idx is None:
            errors.append("[X] heading_2 '🧩 Component Audit' not found")
        else:
            checks_passed.append("[C] Component Audit heading_2 found")

        # Check 2: Component Audit appears after Typography
        if component_audit_idx <= typography_idx:
            errors.append(f"[X] Component Audit (position {component_audit_idx}) should appear after Typography (position {typography_idx})")
        else:
            checks_passed.append("[C] Component Audit correctly positioned after Typography")

        # Check 3: Purple callout with 📐 icon containing today's date
        purple_callout_found = False
        for i in range(component_audit_idx + 1, min(component_audit_idx + 10, len(sorted_blocks))):
            block = sorted_blocks[i]
            if block.get("type") in ["heading2", "heading_2"]:
                break
            if block.get("type") == "callout":
                properties = block.get("properties", {})
                bg_color = properties.get("backgroundColor", block.get("backgroundColor", ""))
                icon = properties.get("icon", block.get("icon", ""))
                content = block.get("content", "")
            
                has_purple_bg = "purple" in bg_color.lower() if bg_color else False
                has_ruler_icon = "📐" in icon if icon else False
                has_audit_text = "audit performed" in content.lower() or "last audit" in content.lower()
            
                if has_purple_bg and (has_ruler_icon or has_audit_text):
                    purple_callout_found = True
                    break
    
        if not purple_callout_found:
            errors.append("[X] Purple callout with 📐 icon and audit date not found")
        else:
            checks_passed.append("[C] Purple callout with audit date found")

        # Check 4: heading_3 'Core Components' with numbered list
        core_components_idx = None
        for i, block in enumerate(sorted_blocks):
            if block.get("type") in ["heading3", "heading_3"]:
                content = block.get("content", "").lower()
                if "core components" in content:
                    core_components_idx = i
                    break
    
        if core_components_idx is None:
            errors.append("[X] heading_3 'Core Components' not found")
        else:
            checks_passed.append("[C] Core Components heading_3 found")

        # Check for numbered list items with counts
        numbered_items = []
        for i in range(core_components_idx + 1, len(sorted_blocks)):
            block = sorted_blocks[i]
            if block.get("type") in ["heading3", "heading_3", "heading2", "heading_2"]:
                break
            if block.get("type") in ["numberedList", "numbered_list", "numbered_list_item", "numbered"]:
                numbered_items.append(block.get("content", "").lower())
    
        # Check for color system, typography scale, spacing system
        has_color = any("color" in item for item in numbered_items)
        has_typography = any("typography" in item for item in numbered_items)
        has_spacing = any("spacing" in item or "8px" in item for item in numbered_items)
    
        if not (has_color and has_typography and has_spacing):
            errors.append(f"[X] Expected Core Components numbered list with color, typography, spacing. Found: color={has_color}, typography={has_typography}, spacing={has_spacing}")
        else:
            checks_passed.append("[C] Core Components numbered list has all required items")

        # Check 5: heading_3 'Usage Guidelines' with bulleted list
        usage_guidelines_idx = None
        for i, block in enumerate(sorted_blocks):
            if block.get("type") in ["heading3", "heading_3"]:
                content = block.get("content", "").lower()
                if "usage guidelines" in content:
                    usage_guidelines_idx = i
                    break
    
        if usage_guidelines_idx is None:
            errors.append("[X] heading_3 'Usage Guidelines' not found")
        else:
            checks_passed.append("[C] Usage Guidelines heading_3 found")

        # Check for bulleted list items
        bulleted_items = []
        for i in range(usage_guidelines_idx + 1, len(sorted_blocks)):
            block = sorted_blocks[i]
            if block.get("type") in ["heading3", "heading_3", "heading2", "heading_2"]:
                break
            if block.get("type") in ["bulletedList", "bulleted_list", "bulleted_list_item", "bulleted"]:
                bulleted_items.append(block.get("content", "").lower())
    
        # Check for required guidelines
        has_8px_grid = any("8px grid" in item for item in bulleted_items)
        has_wcag = any("wcag" in item for item in bulleted_items)
        has_scale = any("scale" in item for item in bulleted_items)
    
        if not (has_8px_grid and has_wcag and has_scale):
            errors.append(f"[X] Expected Usage Guidelines bullets with 8px grid, WCAG, scale. Found: 8px={has_8px_grid}, WCAG={has_wcag}, scale={has_scale}")
        else:
            checks_passed.append("[C] Usage Guidelines bulleted list has all required items")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: Feature Requests Advanced Prioritization
# =============================================================================
def _validate_feature_requests_advanced_prioritization(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Feature Requests page with color-coded todos, Priority Matrix with callouts showing counts."""
    errors: list[str] = []

    checks_passed = []

    # Find Feature Requests page
    try:
        feature_requests = _find_page_by_title(final_state_backend, "Feature Requests")
        if not feature_requests:
            errors.append("[X] Feature Requests page not found")
        else:
            checks_passed.append("[C] Feature Requests page found")

        page_id = feature_requests.get("_id")
        page_blocks = _get_blocks_for_page(final_state_backend, page_id)
        sorted_blocks = sorted(page_blocks, key=lambda b: b.get("order", 0))
        checks_passed.append("[C] Feature Requests page found")

        # Check 1: heading_2 '🎯 Priority Matrix' exists
        priority_matrix_idx = None
        for i, block in enumerate(sorted_blocks):
            if block.get("type") in ["heading2", "heading_2"]:
                content = block.get("content", "")
                if "🎯" in content and "priority matrix" in content.lower():
                    priority_matrix_idx = i
                    break
    
        if priority_matrix_idx is None:
            errors.append("[X] heading_2 '🎯 Priority Matrix' not found")
        else:
            checks_passed.append("[C] Priority Matrix heading_2 found")

        # Check 2: Three heading_3 sections with correct emojis
        high_priority_idx = None
        medium_priority_idx = None
        enhancements_idx = None
    
        for i, block in enumerate(sorted_blocks):
            if block.get("type") in ["heading3", "heading_3"]:
                content = block.get("content", "")
                if "🔴" in content and "high priority" in content.lower():
                    high_priority_idx = i
                elif "🟡" in content and "medium priority" in content.lower():
                    medium_priority_idx = i
                elif "🟢" in content and "enhancement" in content.lower():
                    enhancements_idx = i
    
        if high_priority_idx is None:
            errors.append("[X] heading_3 '🔴 High Priority' not found")
        else:
            checks_passed.append("[C] heading_3 '🔴 High Priority' found")
        if medium_priority_idx is None:
            errors.append("[X] heading_3 '🟡 Medium Priority' not found")
        else:
            checks_passed.append("[C] heading_3 '🟡 Medium Priority' found")
        if enhancements_idx is None:
            errors.append("[X] heading_3 '🟢 Enhancements' not found")
        else:
            checks_passed.append("[C] All three priority section headings found")

        # Check 3: Callouts under each priority section with correct background colors
        def find_callout_after_heading(start_idx, expected_bg_color):
            for i in range(start_idx + 1, min(start_idx + 10, len(sorted_blocks))):
                block = sorted_blocks[i]
                if block.get("type") in ["heading3", "heading_3", "heading2", "heading_2"]:
                    break
                if block.get("type") == "callout":
                    bg_color = block.get("properties", {}).get("backgroundColor", block.get("backgroundColor", ""))
                    if bg_color and expected_bg_color in bg_color.lower():
                        content = block.get("content", "").lower()
                        if "items" in content or "category" in content:
                            return True
            return False
    
        red_callout = find_callout_after_heading(high_priority_idx, "red")
        yellow_callout = find_callout_after_heading(medium_priority_idx, "yellow")
        green_callout = find_callout_after_heading(enhancements_idx, "green")
    
        if not red_callout:
            errors.append("[X] Red background callout under High Priority not found")
        else:
            checks_passed.append("[C] Red background callout under High Priority found")
        if not yellow_callout:
            errors.append("[X] Yellow background callout under Medium Priority not found")
        else:
            checks_passed.append("[C] Yellow background callout under Medium Priority found")
        if not green_callout:
            errors.append("[X] Green background callout under Enhancements not found")
        else:
            checks_passed.append("[C] All three callouts with correct background colors found")

        # Check 4: Paragraph with 'Last prioritization review' at end of Priority Matrix section
        review_paragraph_found = False
        for block in sorted_blocks:
            if block.get("type") in ["paragraph", "text"]:
                content = block.get("content", "").lower()
                if "last prioritization review" in content or "prioritization review" in content:
                    review_paragraph_found = True
                    break
    
        if not review_paragraph_found:
            errors.append("[X] Paragraph with 'Last prioritization review: [date]' not found")
        else:
            checks_passed.append("[C] Last prioritization review paragraph found")

        # Check 5: Verify some todos have color properties (optional - check if any exist)
        todo_blocks = [b for b in sorted_blocks if b.get("type") in ["todo", "to_do", "checkbox"]]
        colored_todos = 0
        for todo in todo_blocks:
            color = todo.get("properties", {}).get("color", todo.get("color", ""))
            if color and color != "default":
                colored_todos += 1
    
        if colored_todos > 0:
            checks_passed.append(f"[C] Found {colored_todos} color-coded todos")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: Weekly Standup Weekly Focus Areas
# =============================================================================
def _validate_weekly_standup_weekly_focus_areas(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Weekly Standup Template with divider before Blockers, Weekly Focus Areas section, and updated blocker todo."""
    errors: list[str] = []

    checks_passed = []

    # Find Weekly Standup Template page
    try:
        standup = _find_page_by_title(final_state_backend, "Weekly Standup Template")
        if not standup:
            errors.append("[X] Weekly Standup Template page not found")
        else:
            checks_passed.append("[C] Weekly Standup Template page found")

        page_id = standup.get("_id")
        page_blocks = _get_blocks_for_page(final_state_backend, page_id)
        sorted_blocks = sorted(page_blocks, key=lambda b: b.get("order", 0))
        checks_passed.append("[C] Weekly Standup Template page found")

        # Find key sections
        blockers_idx = None
        weekly_focus_idx = None
        plan_next_week_idx = None
    
        for i, block in enumerate(sorted_blocks):
            content = block.get("content", "").lower()
            block_type = block.get("type", "")
        
            if block_type in ["heading2", "heading_2"]:
                if "blockers" in content:
                    blockers_idx = i
                elif "weekly focus areas" in content and "🎯" in block.get("content", ""):
                    weekly_focus_idx = i
                elif "plan to do next week" in content or "what i plan" in content:
                    plan_next_week_idx = i
    
        if blockers_idx is None:
            errors.append("[X] Blockers heading not found")
        else:
            checks_passed.append("[C] Blockers heading found")

        # Check 1: Divider immediately before Blockers section
        divider_before_blockers = False
        for i in range(blockers_idx - 1, max(0, blockers_idx - 3), -1):
            if sorted_blocks[i].get("type") == "divider":
                divider_before_blockers = True
                break
    
        if not divider_before_blockers:
            errors.append("[X] Divider immediately before Blockers section not found")
        else:
            checks_passed.append("[C] Divider found before Blockers section")

        # Check 2: heading_2 '🎯 Weekly Focus Areas' exists
        if weekly_focus_idx is None:
            errors.append("[X] heading_2 '🎯 Weekly Focus Areas' not found")
        else:
            checks_passed.append("[C] Weekly Focus Areas heading_2 found")

        # Check 3: Weekly Focus Areas is positioned correctly (before the divider/blockers)
        if weekly_focus_idx >= blockers_idx:
            errors.append(f"[X] Weekly Focus Areas (position {weekly_focus_idx}) should appear before Blockers (position {blockers_idx})")
        else:
            checks_passed.append("[C] Weekly Focus Areas positioned correctly before Blockers")

        # Check 4: Three numbered list items under Weekly Focus Areas
        expected_items = [
            "code quality",
            "documentation",
            "collaboration"
        ]
    
        numbered_items = []
        for i in range(weekly_focus_idx + 1, blockers_idx):
            block = sorted_blocks[i]
            if block.get("type") == "divider":
                break
            if block.get("type") in ["numberedList", "numbered_list", "numbered_list_item", "numbered"]:
                numbered_items.append(block.get("content", "").lower())
    
        found_items = sum(1 for expected in expected_items if any(expected in item for item in numbered_items))
        if found_items < 3:
            errors.append(f"[X] Expected 3 numbered list items (code quality, documentation, collaboration), found {found_items}")
        else:
            checks_passed.append("[C] All 3 Weekly Focus Areas numbered items found")

        # Check 5: Blocker todo now starts with '🚨 URGENT:'
        blocker_todo_updated = False
        for i in range(blockers_idx + 1, len(sorted_blocks)):
            block = sorted_blocks[i]
            if block.get("type") in ["heading2", "heading_2"]:
                break
            if block.get("type") in ["todo", "to_do", "checkbox"]:
                content = block.get("content", "")
                if "🚨" in content and "urgent" in content.lower():
                    blocker_todo_updated = True
                    break
    
        if not blocker_todo_updated:
            errors.append("[X] Blocker todo not updated with '🚨 URGENT:' prefix")
        else:
            checks_passed.append("[C] Blocker todo updated with '🚨 URGENT:' prefix")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: Onboarding Guide 30-Day Checklist
# =============================================================================
def _validate_onboarding_guide_checklist(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Onboarding Guide with 30-Day Onboarding Checklist containing week-based todo items."""
    errors: list[str] = []

    checks_passed = []

    # Find Onboarding Guide page
    try:
        onboarding = _find_page_by_title(final_state_backend, "Onboarding Guide")
        if not onboarding:
            errors.append("[X] Onboarding Guide page not found")
        else:
            checks_passed.append("[C] Onboarding Guide page found")

        page_id = onboarding.get("_id")
        page_blocks = _get_blocks_for_page(final_state_backend, page_id)
        sorted_blocks = sorted(page_blocks, key=lambda b: b.get("order", 0))
        checks_passed.append("[C] Onboarding Guide page found")

        # Check 1: heading_2 '🎯 30-Day Onboarding Checklist' exists
        checklist_idx = None
        for i, block in enumerate(sorted_blocks):
            if block.get("type") in ["heading2", "heading_2"]:
                content = block.get("content", "")
                if "🎯" in content and "30-day onboarding checklist" in content.lower():
                    checklist_idx = i
                    break
    
        if checklist_idx is None:
            errors.append("[X] heading_2 '🎯 30-Day Onboarding Checklist' not found")
        else:
            checks_passed.append("[C] 30-Day Onboarding Checklist heading_2 found")

        # Check 2: Green callout with ✅ icon
        green_callout_found = False
        green_callout_idx = None
        for i in range(checklist_idx + 1, min(checklist_idx + 15, len(sorted_blocks))):
            block = sorted_blocks[i]
            if block.get("type") == "callout":
                properties = block.get("properties", {})
                bg_color = properties.get("backgroundColor", block.get("backgroundColor", ""))
                icon = properties.get("icon", block.get("icon", ""))
            
                has_green_bg = "green" in bg_color.lower() if bg_color else False
                has_check_icon = "✅" in icon if icon else False
            
                if has_green_bg and has_check_icon:
                    green_callout_found = True
                    green_callout_idx = i
                    break
    
        if not green_callout_found:
            errors.append("[X] Green callout with ✅ icon not found")
        else:
            checks_passed.append("[C] Green callout with ✅ icon found")

        # Check 3: heading_3 'Week 1-2: Foundation' with 4 unchecked todos
        week1_2_idx = None
        for i, block in enumerate(sorted_blocks):
            if block.get("type") in ["heading3", "heading_3"]:
                content = block.get("content", "").lower()
                if "week 1-2" in content and "foundation" in content:
                    week1_2_idx = i
                    break
    
        if week1_2_idx is None:
            errors.append("[X] heading_3 'Week 1-2: Foundation' not found")
        else:
            checks_passed.append("[C] Week 1-2: Foundation heading_3 found")

        # Count todos after Week 1-2 heading
        week1_2_todos = []
        for i in range(week1_2_idx + 1, len(sorted_blocks)):
            block = sorted_blocks[i]
            if block.get("type") in ["heading3", "heading_3", "heading2", "heading_2"]:
                break
            if block.get("type") in ["todo", "to_do", "checkbox"]:
                is_checked = block.get("properties", {}).get("checked", False) or block.get("checked", False)
                week1_2_todos.append({"content": block.get("content", ""), "checked": is_checked})
    
        if len(week1_2_todos) < 4:
            errors.append(f"[X] Expected 4 todos under Week 1-2, found {len(week1_2_todos)}")
        else:
            checks_passed.append(f"[C] Found 4 todos under Week 1-2 as expected")
    
        # Verify all are unchecked
        checked_week1_2 = sum(1 for t in week1_2_todos if t["checked"])
        if checked_week1_2 > 0:
            errors.append(f"[X] Week 1-2 todos should be unchecked, but {checked_week1_2} are checked")
        else:
            checks_passed.append(f"[C] Week 1-2 has {len(week1_2_todos)} unchecked todos")

        # Check 4: heading_3 'Week 3-4: Deep Dive' with 3 unchecked todos
        week3_4_idx = None
        for i, block in enumerate(sorted_blocks):
            if block.get("type") in ["heading3", "heading_3"]:
                content = block.get("content", "").lower()
                if "week 3-4" in content and "deep dive" in content:
                    week3_4_idx = i
                    break
    
        if week3_4_idx is None:
            errors.append("[X] heading_3 'Week 3-4: Deep Dive' not found")
        else:
            checks_passed.append("[C] Week 3-4: Deep Dive heading_3 found")

        # Count todos after Week 3-4 heading
        week3_4_todos = []
        for i in range(week3_4_idx + 1, len(sorted_blocks)):
            block = sorted_blocks[i]
            if block.get("type") in ["heading3", "heading_3", "heading2", "heading_2"]:
                break
            if block.get("type") in ["todo", "to_do", "checkbox"]:
                is_checked = block.get("properties", {}).get("checked", False) or block.get("checked", False)
                week3_4_todos.append({"content": block.get("content", ""), "checked": is_checked})
    
        if len(week3_4_todos) < 3:
            errors.append(f"[X] Expected 3 todos under Week 3-4, found {len(week3_4_todos)}")
        else:
            checks_passed.append(f"[C] Found 3 todos under Week 3-4 as expected")
    
        # Verify all are unchecked
        checked_week3_4 = sum(1 for t in week3_4_todos if t["checked"])
        if checked_week3_4 > 0:
            errors.append(f"[X] Week 3-4 todos should be unchecked, but {checked_week3_4} are checked")
        else:
            checks_passed.append(f"[C] Week 3-4 has {len(week3_4_todos)} unchecked todos")

        # Check 5: Verify some expected todo content with emojis
        expected_week1_items = ["email", "it setup", "meet", "handbook"]
        expected_week3_items = ["training", "shadow", "document"]
    
        all_week1_content = " ".join([t["content"].lower() for t in week1_2_todos])
        all_week3_content = " ".join([t["content"].lower() for t in week3_4_todos])
    
        found_week1 = sum(1 for item in expected_week1_items if item in all_week1_content)
        found_week3 = sum(1 for item in expected_week3_items if item in all_week3_content)
    
        if found_week1 < 3:
            errors.append(f"[X] Week 1-2 todos missing expected content, found {found_week1}/4 items")
        else:
            checks_passed.append(f"[C] Week 1-2 todos has expected content, found {found_week1}/4 items")
        if found_week3 < 2:
            errors.append(f"[X] Week 3-4 todos missing expected content, found {found_week3}/3 items")
        else:
            checks_passed.append("[C] Todo content matches expected items")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: Code Examples DevOps Section
# =============================================================================
def _validate_code_examples_devops_section(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Code Examples Repository with new DevOps Examples section between Typescript and Bash."""
    errors: list[str] = []

    checks_passed = []

    # Find Code Examples Repository page
    try:
        code_examples = _find_page_by_title(final_state_backend, "Code Examples Repository")
        if not code_examples:
            errors.append("[X] Code Examples Repository page not found")
        else:
            checks_passed.append("[C] Code Examples Repository page found")

        page_id = code_examples.get("_id")
        page_blocks = _get_blocks_for_page(final_state_backend, page_id)
        sorted_blocks = sorted(page_blocks, key=lambda b: b.get("order", 0))
        checks_passed.append("[C] Code Examples Repository page found")

        # Find section headings
        typescript_idx = None
        devops_idx = None
        bash_idx = None

        for i, block in enumerate(sorted_blocks):
            if block.get("type") in ["heading2", "heading_2"]:
                content = block.get("content", "").lower()
                if "typescript" in content:
                    typescript_idx = i
                elif "devops" in content and "🔧" in block.get("content", ""):
                    devops_idx = i
                elif "bash" in content:
                    bash_idx = i

        # Check 1: DevOps section exists with correct emoji
        if devops_idx is None:
            errors.append("[X] heading_2 '🔧 DevOps Examples' not found")
        else:
            checks_passed.append("[C] DevOps Examples heading_2 found with 🔧 emoji")

        # Check 2: DevOps is between Typescript and Bash
        if typescript_idx is not None and bash_idx is not None:
            if not (typescript_idx < devops_idx < bash_idx):
                errors.append(f"[X] DevOps section (pos {devops_idx}) must be between Typescript (pos {typescript_idx}) and Bash (pos {bash_idx})")
            else:
                checks_passed.append("[C] DevOps section positioned correctly between Typescript and Bash")
        elif typescript_idx is not None:
            if devops_idx <= typescript_idx:
                errors.append("[X] DevOps section should come after Typescript section")
            else:
                checks_passed.append("[C] DevOps section positioned after Typescript")

        # Check 3: YAML code block with correct content
        yaml_code_found = False
        for i in range(devops_idx + 1, min(devops_idx + 10, len(sorted_blocks))):
            block = sorted_blocks[i]
            if block.get("type") in ["heading2", "heading_2"]:
                break
            if block.get("type") == "code":
                properties = block.get("properties", {})
                language = properties.get("language", block.get("language", ""))
                content = block.get("content", "")
            
                if "yaml" in language.lower():
                    # Check for required YAML content
                    required_terms = ["apiVersion", "Deployment", "nginx-deployment", "replicas"]
                    found_terms = sum(1 for term in required_terms if term in content)
                    if found_terms >= 3:
                        yaml_code_found = True
                        checks_passed.append("[C] YAML code block with Kubernetes deployment found")
                        break

        if not yaml_code_found:
            errors.append("[X] Code block with language 'yaml' and Kubernetes deployment content not found")
        else:
            checks_passed.append("[C] Code block with language 'yaml' and Kubernetes deployment content found")

        # Check 4: Description paragraph
        desc_paragraph_found = False
        for i in range(devops_idx + 1, min(devops_idx + 10, len(sorted_blocks))):
            block = sorted_blocks[i]
            if block.get("type") in ["heading2", "heading_2"]:
                break
            if block.get("type") in ["paragraph", "text"]:
                content = block.get("content", "").lower()
                if "common devops pattern" in content and "production code" in content:
                    desc_paragraph_found = True
                    checks_passed.append("[C] Description paragraph found")
                    break

        if not desc_paragraph_found:
            errors.append("[X] Paragraph 'Common DevOps pattern for production code.' not found")
        else:
            checks_passed.append("[C] Paragraph 'Common DevOps pattern for production code.' found")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: Research Notes Progress Tracker
# =============================================================================
def _validate_research_notes_progress_tracker(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Research Notes page with progress tracker and archived duplicate."""
    errors: list[str] = []

    checks_passed = []

    # Check 1: Find Research Notes archive page
    try:
        archive_pages = _find_pages_with_all_title_patterns(final_state_backend, ["research notes", "archive"])
        if not archive_pages:
            errors.append("[X] Research Notes archive page not found")
        else:
            checks_passed.append("[C] Research Notes archive page created")

        # Check 2: Find original Research Notes page
        research_notes = _find_page_by_title(final_state_backend, "Research Notes")
        if not research_notes:
            errors.append("[X] Original Research Notes page not found")
        else:
            checks_passed.append("[C] Original Research Notes page found")

        page_id = research_notes.get("_id")
        page_blocks = _get_blocks_for_page(final_state_backend, page_id)
        sorted_blocks = sorted(page_blocks, key=lambda b: b.get("order", 0))
        checks_passed.append("[C] Research Notes page found")

        # Check 3: Progress Tracker heading_2 with emoji
        tracker_idx = None
        for i, block in enumerate(sorted_blocks):
            if block.get("type") in ["heading2", "heading_2"]:
                content = block.get("content", "")
                if "🔬" in content and "research progress tracker" in content.lower():
                    tracker_idx = i
                    break

        if tracker_idx is None:
            errors.append("[X] heading_2 '🔬 Research Progress Tracker' not found")
        else:
            checks_passed.append("[C] Research Progress Tracker heading found")

        # Check 4: Green callout with research areas count
        green_callout_found = False
        for i in range(tracker_idx + 1, min(tracker_idx + 10, len(sorted_blocks))):
            block = sorted_blocks[i]
            if block.get("type") in ["heading2", "heading_2", "heading3", "heading_3"]:
                break
            if block.get("type") == "callout":
                properties = block.get("properties", {})
                bg_color = properties.get("backgroundColor", block.get("backgroundColor", ""))
                icon = properties.get("icon", block.get("icon", ""))
                content = block.get("content", "")
            
                has_green_bg = "green" in bg_color.lower() if bg_color else False
                has_chart_icon = "📊" in icon if icon else False
                has_count_text = "research areas explored" in content.lower()
            
                if has_green_bg and has_chart_icon and has_count_text:
                    green_callout_found = True
                    checks_passed.append("[C] Green callout with research areas count found")
                    break

        if not green_callout_found:
            errors.append("[X] Green callout with '📊' icon and 'Research areas explored:' text not found")
        else:
            checks_passed.append("[C] Green callout with '📊' icon and 'Research areas explored:' text found")

        # Check 5: Research Priorities heading_3
        priorities_idx = None
        for i, block in enumerate(sorted_blocks):
            if block.get("type") in ["heading3", "heading_3"]:
                content = block.get("content", "")
                if "🎯" in content and "research priorities" in content.lower():
                    priorities_idx = i
                    break

        if priorities_idx is None:
            errors.append("[X] heading_3 '🎯 Research Priorities' not found")
        else:
            checks_passed.append("[C] Research Priorities heading found")

        # Check 6: Three unchecked todo blocks
        todo_count = 0
        for i in range(priorities_idx + 1, min(priorities_idx + 10, len(sorted_blocks))):
            block = sorted_blocks[i]
            if block.get("type") in ["heading2", "heading_2", "heading3", "heading_3"]:
                break
            if block.get("type") in ["todo", "to_do", "checkbox"]:
                is_checked = block.get("properties", {}).get("checked", False) or block.get("checked", False)
                if not is_checked:
                    todo_count += 1

        if todo_count < 3:
            errors.append(f"[X] Expected at least 3 unchecked todos under Research Priorities, found {todo_count}")
        else:
            checks_passed.append(f"[C] Found {todo_count} unchecked todos under Research Priorities")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: Design System Component Tracking
# =============================================================================
def _validate_design_system_component_tracking(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Design System page with component tracking system and metrics."""
    errors: list[str] = []

    checks_passed = []

    # Find Design System page
    try:
        design_system = _find_page_by_title(final_state_backend, "Design System")
        if not design_system:
            errors.append("[X] Design System page not found")
        else:
            checks_passed.append("[C] Design System page found")

        page_id = design_system.get("_id")
        page_blocks = _get_blocks_for_page(final_state_backend, page_id)
        sorted_blocks = sorted(page_blocks, key=lambda b: b.get("order", 0))
        checks_passed.append("[C] Design System page found")

        # Check 1: heading_1 '🎨 Design System Overview'
        overview_heading = None
        for block in sorted_blocks:
            if block.get("type") in ["heading1", "heading_1"]:
                content = block.get("content", "")
                if "🎨" in content and "design system overview" in content.lower():
                    overview_heading = block
                    break

        if not overview_heading:
            errors.append("[X] heading_1 '🎨 Design System Overview' not found")
        else:
            checks_passed.append("[C] Design System Overview heading_1 found")

        # Check 2: heading_2 '📊 System Metrics'
        metrics_idx = None
        for i, block in enumerate(sorted_blocks):
            if block.get("type") in ["heading2", "heading_2"]:
                content = block.get("content", "")
                if "📊" in content and "system metrics" in content.lower():
                    metrics_idx = i
                    break

        if metrics_idx is None:
            errors.append("[X] heading_2 '📊 System Metrics' not found")
        else:
            checks_passed.append("[C] System Metrics heading_2 found")

        # Check 3: heading_2 '🔧 Implementation Status'
        impl_status_idx = None
        for i, block in enumerate(sorted_blocks):
            if block.get("type") in ["heading2", "heading_2"]:
                content = block.get("content", "")
                if "🔧" in content and "implementation status" in content.lower():
                    impl_status_idx = i
                    break

        if impl_status_idx is None:
            errors.append("[X] heading_2 '🔧 Implementation Status' not found")
        else:
            checks_passed.append("[C] Implementation Status heading_2 found")

        # Check 4: Divider between metrics and implementation
        divider_found = False
        if metrics_idx is not None and impl_status_idx is not None:
            for i in range(metrics_idx + 1, impl_status_idx):
                if sorted_blocks[i].get("type") == "divider":
                    divider_found = True
                    break

        if not divider_found:
            errors.append("[X] Divider between metrics and implementation status not found")
        else:
            checks_passed.append("[C] Divider found between sections")

        # Check 5: Numbered list with implementation items
        impl_items = []
        if impl_status_idx is not None:
            for i in range(impl_status_idx + 1, min(impl_status_idx + 15, len(sorted_blocks))):
                block = sorted_blocks[i]
                if block.get("type") in ["heading2", "heading_2", "callout"]:
                    break
                if block.get("type") in ["numberedList", "numbered_list", "numbered_list_item", "numbered"]:
                    impl_items.append(block.get("content", ""))

        expected_statuses = ["color system", "typography", "component library", "design tokens"]
        found_statuses = sum(1 for exp in expected_statuses if any(exp in item.lower() for item in impl_items))
    
        if found_statuses < 4:
            errors.append(f"[X] Expected 4 implementation status items, found {found_statuses}")
        else:
            checks_passed.append("[C] All 4 implementation status items found")

        # Check 6: Red callout at end with critical message
        red_callout_found = False
        for block in reversed(sorted_blocks):
            if block.get("type") == "callout":
                properties = block.get("properties", {})
                bg_color = properties.get("backgroundColor", block.get("backgroundColor", ""))
                icon = properties.get("icon", block.get("icon", ""))
                content = block.get("content", "")
            
                has_red_bg = "red" in bg_color.lower() if bg_color else False
                has_lightning_icon = "⚡" in icon if icon else False
                has_critical_text = "critical" in content.lower()
            
                if has_red_bg and has_lightning_icon and has_critical_text:
                    red_callout_found = True
                    checks_passed.append("[C] Red callout with critical message found")
                    break

        if not red_callout_found:
            errors.append("[X] Red callout with ⚡ icon and 'Critical' message not found at end of page")
        else:
            checks_passed.append("[C] Red callout with ⚡ icon and 'Critical' message found at end of page")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: Bug Tracker Priority Swap
# =============================================================================
def _validate_bug_tracker_priority_swap(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Bug Tracker page with swapped Critical and Low Priority sections."""
    errors: list[str] = []

    checks_passed = []

    # Find Bug Tracker page
    try:
        bug_tracker = _find_page_by_title(final_state_backend, "Bug Tracker")
        if not bug_tracker:
            errors.append("[X] Bug Tracker page not found")
        else:
            checks_passed.append("[C] Bug Tracker page found")

        page_id = bug_tracker.get("_id")
        page_blocks = _get_blocks_for_page(final_state_backend, page_id)
        sorted_blocks = sorted(page_blocks, key=lambda b: b.get("order", 0))
        checks_passed.append("[C] Bug Tracker page found")

        # Find section headings and their positions
        low_priority_idx = None
        medium_priority_idx = None
        critical_idx = None

        for i, block in enumerate(sorted_blocks):
            if block.get("type") in ["heading2", "heading_2"]:
                content = block.get("content", "").lower()
                if "low priority" in content:
                    low_priority_idx = i
                elif "medium priority" in content:
                    medium_priority_idx = i
                elif "critical" in content:
                    critical_idx = i

        # Check 1: Low Priority section comes first (was swapped)
        if low_priority_idx is None:
            errors.append("[X] Low Priority section heading not found")
        else:
            checks_passed.append("[C] Low Priority section heading found")
        if medium_priority_idx is None:
            errors.append("[X] Medium Priority section heading not found")
        else:
            checks_passed.append("[C] Medium Priority section heading found")
        if critical_idx is None:
            errors.append("[X] Critical Bugs section heading not found")
        else:
            checks_passed.append("[C] Critical Bugs section heading found")

        # Verify order: Low Priority < Medium Priority < Critical
        if not (low_priority_idx < medium_priority_idx < critical_idx):
            errors.append(f"[X] Section order incorrect. Expected: Low Priority ({low_priority_idx}) < Medium Priority ({medium_priority_idx}) < Critical ({critical_idx})")
        else:
            checks_passed.append("[C] Sections reordered correctly: Low Priority first, Critical last")

        # Check 2: Red callout before first todo in Low Priority section
        red_callout_found = False
        first_todo_in_low = None
    
        for i in range(low_priority_idx + 1, medium_priority_idx):
            block = sorted_blocks[i]
            if block.get("type") in ["todo", "to_do", "checkbox"]:
                first_todo_in_low = i
                break

        if first_todo_in_low is not None:
            # Check if there's a red callout before it
            for i in range(low_priority_idx + 1, first_todo_in_low):
                block = sorted_blocks[i]
                if block.get("type") == "callout":
                    properties = block.get("properties", {})
                    bg_color = properties.get("backgroundColor", block.get("backgroundColor", ""))
                    icon = properties.get("icon", block.get("icon", ""))
                    content = block.get("content", "")
                
                    has_red_bg = "red" in bg_color.lower() if bg_color else False
                    has_alert_icon = "🚨" in icon if icon else False
                    has_urgent_text = "urgent" in content.lower() and "priority escalation" in content.lower()
                
                    if has_red_bg and has_alert_icon and has_urgent_text:
                        red_callout_found = True
                        checks_passed.append("[C] Red callout with URGENT message found before first todo")
                        break

        if not red_callout_found:
            errors.append("[X] Red callout with '🚨' icon and 'URGENT: These bugs need immediate attention due to priority escalation' not found")
        else:
            checks_passed.append("[C] Red callout with '🚨' icon and 'URGENT: These bugs need immediate attention due to priority escalation' found")

        # Check 3: New memory leak todo in Medium Priority section
        memory_leak_todo_found = False
        first_medium_todo_is_memory_leak = False
        medium_todos = []
    
        for i in range(medium_priority_idx + 1, critical_idx):
            block = sorted_blocks[i]
            if block.get("type") in ["todo", "to_do", "checkbox"]:
                content = block.get("content", "")
                is_checked = block.get("properties", {}).get("checked", False) or block.get("checked", False)
                medium_todos.append({"content": content, "checked": is_checked, "index": i})
            
                if "memory leak" in content.lower() and "background workers" in content.lower():
                    memory_leak_todo_found = True
                    if len(medium_todos) == 1:
                        first_medium_todo_is_memory_leak = True

        if not memory_leak_todo_found:
            errors.append("[X] Todo '🔍 Investigate memory leak in background workers' not found in Medium Priority section")
        else:
            checks_passed.append("[C] Todo '🔍 Investigate memory leak in background workers' found in Medium Priority section")

        if not first_medium_todo_is_memory_leak:
            errors.append("[X] Memory leak todo should be the first item in Medium Priority section")
        else:
            checks_passed.append("[C] Memory leak todo should be the first item in Medium Priority section")
    
        # Verify it's unchecked
        memory_leak_checked = medium_todos[0]["checked"] if medium_todos else False
        if memory_leak_checked:
            errors.append("[X] Memory leak todo should be unchecked")
        else:
            checks_passed.append("[C] Memory leak todo should be unchecked")
    
        checks_passed.append("[C] Memory leak todo added as first unchecked item in Medium Priority")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: Weekly Standup Action Items Tracking
# =============================================================================
def _validate_weekly_standup_action_items_tracking(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Weekly Standup Template with Action Items Tracking section and completion rate."""
    errors: list[str] = []

    checks_passed = []

    # Find Weekly Standup Template page
    try:
        standup = _find_page_by_title(final_state_backend, "Weekly Standup Template")
        if not standup:
            errors.append("[X] Weekly Standup Template page not found")
        else:
            checks_passed.append("[C] Weekly Standup Template page found")

        page_id = standup.get("_id")
        page_blocks = _get_blocks_for_page(final_state_backend, page_id)
        sorted_blocks = sorted(page_blocks, key=lambda b: b.get("order", 0))
        checks_passed.append("[C] Weekly Standup Template page found")

        # Find Blockers and Action Items Tracking sections
        blockers_idx = None
        action_items_idx = None

        for i, block in enumerate(sorted_blocks):
            if block.get("type") in ["heading2", "heading_2"]:
                content = block.get("content", "").lower()
                if "blockers" in content:
                    blockers_idx = i
                elif "action items tracking" in content:
                    action_items_idx = i

        # Check 1: Action Items Tracking heading exists
        if action_items_idx is None:
            errors.append("[X] heading2 'Action Items Tracking' not found")
        else:
            checks_passed.append("[C] Action Items Tracking heading found")

        # Check 2: Action Items Tracking comes after Blockers
        if blockers_idx is not None and action_items_idx <= blockers_idx:
            errors.append(f"[X] Action Items Tracking (pos {action_items_idx}) should come after Blockers (pos {blockers_idx})")
        else:
            checks_passed.append("[C] Action Items Tracking positioned after Blockers")

        # Check 3: Yellow callout with completion rate
        yellow_callout_found = False
        completion_rate_correct = False
    
        for i in range(action_items_idx + 1, min(action_items_idx + 10, len(sorted_blocks))):
            block = sorted_blocks[i]
            if block.get("type") in ["heading2", "heading_2"]:
                break
            if block.get("type") == "callout":
                properties = block.get("properties", {})
                bg_color = properties.get("backgroundColor", block.get("backgroundColor", ""))
                icon = properties.get("icon", block.get("icon", ""))
                content = block.get("content", "")
            
                has_yellow_bg = "yellow" in bg_color.lower() if bg_color else False
                has_chart_icon = "📊" in icon if icon else False
                has_rate_text = "weekly completion rate" in content.lower()
            
                if has_yellow_bg and has_chart_icon and has_rate_text:
                    yellow_callout_found = True
                    # Check for percentage
                    if "%" in content:
                        completion_rate_correct = True
                    checks_passed.append("[C] Yellow callout with completion rate found")
                    break

        if not yellow_callout_found:
            errors.append("[X] Yellow callout with '📊' icon and 'Weekly completion rate' not found")
        else:
            checks_passed.append("[C] Yellow callout with '📊' icon and 'Weekly completion rate' found")

        if not completion_rate_correct:
            errors.append("[X] Callout should contain completion percentage")
        else:
            checks_passed.append("[C] Callout should contain completion percentage")

        # Check 4: Three specific todo items
        expected_todos = [
            ("migrate legacy codebase", "typescript"),
            ("performance bottleneck", "search module"),
            ("api documentation", "v2 endpoints")
        ]
    
        found_todos = 0
        for i in range(action_items_idx + 1, len(sorted_blocks)):
            block = sorted_blocks[i]
            if block.get("type") in ["heading2", "heading_2"]:
                break
            if block.get("type") in ["todo", "to_do", "checkbox"]:
                content = block.get("content", "").lower()
                for term1, term2 in expected_todos:
                    if term1 in content and term2 in content:
                        found_todos += 1
                        break

        if found_todos < 3:
            errors.append(f"[X] Expected 3 specific action item todos, found {found_todos}")
        else:
            checks_passed.append("[C] All 3 action item todos found")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: Product Requirements Section Timestamps
# =============================================================================
def _validate_product_requirements_section_timestamps(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Comprehensive Product Requirements Document with section timestamps and length warnings."""
    errors: list[str] = []

    checks_passed = []

    # Find the PRD page
    try:
        prd_page = _find_page_by_title(final_state_backend, "Comprehensive Product Requirements")
        if not prd_page:
            prd_page = _find_page_by_title(final_state_backend, "Product Requirements Document")
        if not prd_page:
            errors.append("[X] Comprehensive Product Requirements Document page not found")
        else:
            checks_passed.append("[C] Comprehensive Product Requirements Document page found")

        page_id = prd_page.get("_id")
        page_blocks = _get_blocks_for_page(final_state_backend, page_id)
        sorted_blocks = sorted(page_blocks, key=lambda b: b.get("order", 0))
        checks_passed.append("[C] Product Requirements Document page found")

        # Find heading_2 blocks
        heading2_indices = []
        for i, block in enumerate(sorted_blocks):
            if block.get("type") in ["heading2", "heading_2"]:
                heading2_indices.append(i)

        if len(heading2_indices) == 0:
            errors.append("[X] No heading_2 blocks found on the page")
        else:
            checks_passed.append(f"[C] Found {len(heading2_indices)} heading_2 blocks")

        # Check 1: Summary paragraph at top with section count
        summary_found = False
        for i, block in enumerate(sorted_blocks[:10]):
            if block.get("type") in ["paragraph", "text"]:
                content = block.get("content", "").lower()
                if "document sections" in content and "last full review" in content:
                    summary_found = True
                    checks_passed.append("[C] Summary paragraph with section count found at top")
                    break

        if not summary_found:
            errors.append("[X] Summary paragraph 'Document sections: [N] | Last full review: [date]' not found at top")
        else:
            checks_passed.append("[C] Summary paragraph 'Document sections: [N] | Last full review: [date]' found at top")

        # Check 2: Gray callouts after heading_2 blocks with timestamps
        timestamp_callouts = 0
        for h2_idx in heading2_indices:
            # Look for callout within 3 blocks after heading
            for check_idx in range(h2_idx + 1, min(h2_idx + 4, len(sorted_blocks))):
                block = sorted_blocks[check_idx]
                if block.get("type") in ["heading2", "heading_2", "heading3", "heading_3"]:
                    break
                if block.get("type") == "callout":
                    properties = block.get("properties", {})
                    bg_color = properties.get("backgroundColor", block.get("backgroundColor", ""))
                    icon = properties.get("icon", block.get("icon", ""))
                    content = block.get("content", "")
                
                    has_gray_bg = "gray" in bg_color.lower() if bg_color else False
                    has_pin_icon = "📍" in icon if icon else False
                    has_update_text = "section last updated" in content.lower()
                
                    if has_gray_bg and has_pin_icon and has_update_text:
                        timestamp_callouts += 1
                        break

        if timestamp_callouts == 0:
            errors.append("[X] No gray callouts with '📍' icon and section timestamps found after heading_2 blocks")
        else:
            checks_passed.append("[C] gray callouts with '📍' icon and section timestamps found after heading_2 blocks")
    
        checks_passed.append(f"[C] Found {timestamp_callouts} timestamp callouts after heading_2 blocks")

        # Check 3: Yellow warning callouts for lengthy sections (optional - depends on content)
        # This check is lenient since it depends on actual section lengths
        warning_callouts = 0
        for block in sorted_blocks:
            if block.get("type") == "callout":
                properties = block.get("properties", {})
                bg_color = properties.get("backgroundColor", block.get("backgroundColor", ""))
                icon = properties.get("icon", block.get("icon", ""))
                content = block.get("content", "")
            
                has_yellow_bg = "yellow" in bg_color.lower() if bg_color else False
                has_warning_icon = "⚠️" in icon if icon else False
                has_lengthy_text = "lengthy" in content.lower() and "blocks" in content.lower()
            
                if has_yellow_bg and has_warning_icon and has_lengthy_text:
                    warning_callouts += 1

        if warning_callouts > 0:
            checks_passed.append(f"[C] Found {warning_callouts} warning callouts for lengthy sections")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: API Documentation Endpoints Reorganization
# =============================================================================
def _validate_api_documentation_endpoints_reorganization(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate API Documentation page with reorganized Endpoints section."""
    errors: list[str] = []

    checks_passed = []

    # Find API Documentation page
    try:
        api_docs = _find_page_by_title(final_state_backend, "API Documentation")
        if not api_docs:
            errors.append("[X] API Documentation page not found")
        else:
            checks_passed.append("[C] API Documentation page found")

        page_id = api_docs.get("_id")
        page_blocks = _get_blocks_for_page(final_state_backend, page_id)
        sorted_blocks = sorted(page_blocks, key=lambda b: b.get("order", 0))
        checks_passed.append("[C] API Documentation page found")

        # Find Endpoints heading
        endpoints_idx = None
        for i, block in enumerate(sorted_blocks):
            if block.get("type") in ["heading2", "heading_2"]:
                content = block.get("content", "").lower()
                if "endpoints" in content:
                    endpoints_idx = i
                    break

        if endpoints_idx is None:
            errors.append("[X] Endpoints heading not found")
        else:
            checks_passed.append("[C] Endpoints section found")

        # Check 1: Base URL paragraph after Endpoints heading
        base_url_found = False
        for i in range(endpoints_idx + 1, min(endpoints_idx + 5, len(sorted_blocks))):
            block = sorted_blocks[i]
            if block.get("type") in ["heading3", "heading_3"]:
                break
            if block.get("type") in ["paragraph", "text"]:
                content = block.get("content", "")
                if "base url" in content.lower() and "api.acme-corp.com" in content.lower():
                    base_url_found = True
                    checks_passed.append("[C] Base URL paragraph found")
                    break

        if not base_url_found:
            errors.append("[X] Paragraph 'Base URL: https://api.acme-corp.com/v1' not found after Endpoints heading")
        else:
            checks_passed.append("[C] Paragraph 'Base URL: https://api.acme-corp.com/v1' found after Endpoints heading")

        # Check 2: User Management heading_3
        user_mgmt_idx = None
        for i, block in enumerate(sorted_blocks):
            if block.get("type") in ["heading3", "heading_3"]:
                content = block.get("content", "").lower()
                if "user management" in content:
                    user_mgmt_idx = i
                    break

        if user_mgmt_idx is None:
            errors.append("[X] heading_3 'User Management' not found")
        else:
            checks_passed.append("[C] User Management heading found")

        # Check 3: Page Management heading_3
        page_mgmt_idx = None
        for i, block in enumerate(sorted_blocks):
            if block.get("type") in ["heading3", "heading_3"]:
                content = block.get("content", "").lower()
                if "page management" in content:
                    page_mgmt_idx = i
                    break

        if page_mgmt_idx is None:
            errors.append("[X] heading_3 'Page Management' not found")
        else:
            checks_passed.append("[C] Page Management heading found")

        # Check 4: PUT endpoint under Page Management
        put_endpoint_found = False
        if page_mgmt_idx is not None:
            for i in range(page_mgmt_idx + 1, len(sorted_blocks)):
                block = sorted_blocks[i]
                if block.get("type") in ["heading2", "heading_2", "heading3", "heading_3"]:
                    break
                content = block.get("content", "").lower()
                if "put" in content and "/api/pages" in content:
                    put_endpoint_found = True
                    checks_passed.append("[C] PUT /api/pages/:id endpoint found")
                    break

        if not put_endpoint_found:
            errors.append("[X] PUT /api/pages/:id endpoint not found under Page Management")
        else:
            checks_passed.append("[C] PUT /api/pages/:id endpoint found under Page Management")

        # Check 5: Bash code block with curl command
        curl_code_found = False
        for block in sorted_blocks:
            if block.get("type") == "code":
                properties = block.get("properties", {})
                language = properties.get("language", block.get("language", ""))
                content = block.get("content", "")
            
                has_bash = "bash" in language.lower() if language else False
                has_curl = "curl" in content.lower()
                has_auth = "authorization" in content.lower() or "bearer" in content.lower()
            
                if has_bash and has_curl and has_auth:
                    curl_code_found = True
                    checks_passed.append("[C] Bash code block with curl command found")
                    break

        if not curl_code_found:
            errors.append("[X] Code block with language 'bash' and curl command with Authorization header not found")
        else:
            checks_passed.append("[C] Code block with language 'bash' and curl command with Authorization header found")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: Getting Started Task Analysis
# =============================================================================
def _validate_getting_started_task_analysis(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Getting Started page with task analysis and Advanced Tasks section."""
    errors: list[str] = []

    checks_passed = []

    # Find Getting Started page
    try:
        getting_started = _find_page_by_title(final_state_backend, "Getting Started")
        if not getting_started:
            errors.append("[X] Getting Started page not found")
        else:
            checks_passed.append("[C] Getting Started page found")

        page_id = getting_started.get("_id")
        page_blocks = _get_blocks_for_page(final_state_backend, page_id)
        sorted_blocks = sorted(page_blocks, key=lambda b: b.get("order", 0))
        checks_passed.append("[C] Getting Started page found")

        # Find main heading
        main_heading_idx = None
        for i, block in enumerate(sorted_blocks):
            if block.get("type") in ["heading1", "heading_1"]:
                content = block.get("content", "").lower()
                if "welcome" in content or "acme corp" in content:
                    main_heading_idx = i
                    break

        # Check 1: Blue callout with progress stats near top
        progress_callout_found = False
        for i, block in enumerate(sorted_blocks[:15]):
            if block.get("type") == "callout":
                properties = block.get("properties", {})
                bg_color = properties.get("backgroundColor", block.get("backgroundColor", ""))
                icon = properties.get("icon", block.get("icon", ""))
                content = block.get("content", "")
            
                has_blue_bg = "blue" in bg_color.lower() if bg_color else False
                has_chart_icon = "📊" in icon if icon else False
                has_progress_text = "quick start progress" in content.lower()
                has_stats = "of" in content and "completed" in content.lower() and "%" in content
            
                if has_blue_bg and has_chart_icon and has_progress_text and has_stats:
                    progress_callout_found = True
                    checks_passed.append("[C] Blue callout with progress stats found near top")
                    break

        if not progress_callout_found:
            errors.append("[X] Blue callout with '📊' icon and 'Quick Start Progress: [X] of [Y] tasks completed ([Z]%)' not found")
        else:
            checks_passed.append("[C] Blue callout with '📊' icon and 'Quick Start Progress: [X] of [Y] tasks completed ([Z]%)' found")

        # Check 2: Divider near end
        divider_found = False
        divider_idx = None
        for i in range(len(sorted_blocks) - 15, len(sorted_blocks)):
            if i >= 0 and sorted_blocks[i].get("type") == "divider":
                divider_found = True
                divider_idx = i
                break

        if not divider_found:
            errors.append("[X] Divider near end of page not found")
        else:
            checks_passed.append("[C] Divider found near end of page")

        # Check 3: heading_2 '🎯 Advanced Tasks'
        advanced_tasks_idx = None
        for i, block in enumerate(sorted_blocks):
            if block.get("type") in ["heading2", "heading_2"]:
                content = block.get("content", "")
                if "🎯" in content and "advanced tasks" in content.lower():
                    advanced_tasks_idx = i
                    break

        if advanced_tasks_idx is None:
            errors.append("[X] heading_2 '🎯 Advanced Tasks' not found")
        else:
            checks_passed.append("[C] Advanced Tasks heading found")

        # Check 4: Four unchecked todos under Advanced Tasks
        expected_todos = [
            "configure workspace",
            "invite team",
            "download mobile",
            "integrate with external"
        ]
    
        found_todos = 0
        unchecked_todos = 0
    
        for i in range(advanced_tasks_idx + 1, len(sorted_blocks)):
            block = sorted_blocks[i]
            if block.get("type") in ["heading2", "heading_2"]:
                break
            if block.get("type") in ["todo", "to_do", "checkbox"]:
                content = block.get("content", "").lower()
                is_checked = block.get("properties", {}).get("checked", False) or block.get("checked", False)
            
                for expected in expected_todos:
                    if expected in content:
                        found_todos += 1
                        if not is_checked:
                            unchecked_todos += 1
                        break

        if found_todos < 4:
            errors.append(f"[X] Expected 4 specific todos under Advanced Tasks, found {found_todos}")
        else:
            checks_passed.append(f"[C] Found 4 specific todos under Advanced Tasks as expected")
    
        if unchecked_todos < 4:
            errors.append(f"[X] All 4 Advanced Tasks todos should be unchecked, found {unchecked_todos} unchecked")
        else:
            checks_passed.append(f"[C] All 4 Advanced Tasks todos should be unchecked, found {unchecked_todos} unchecked")
    
        checks_passed.append("[C] All 4 unchecked Advanced Tasks todos found")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: Code Examples Rust Section
# =============================================================================
def _validate_code_examples_rust_section(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Code Examples Repository with new Rust Examples section after Typescript."""
    errors: list[str] = []

    checks_passed = []

    # Find Code Examples Repository page
    try:
        code_examples = _find_page_by_title(final_state_backend, "Code Examples Repository")
        if not code_examples:
            errors.append("[X] Code Examples Repository page not found")
        else:
            checks_passed.append("[C] Code Examples Repository page found")

        page_id = code_examples.get("_id")
        page_blocks = _get_blocks_for_page(final_state_backend, page_id)
        sorted_blocks = sorted(page_blocks, key=lambda b: b.get("order", 0))
        checks_passed.append("[C] Code Examples Repository page found")

        # Find section headings
        typescript_idx = None
        rust_idx = None
        bash_idx = None

        for i, block in enumerate(sorted_blocks):
            if block.get("type") in ["heading2", "heading_2"]:
                content = block.get("content", "").lower()
                if "typescript" in content:
                    typescript_idx = i
                elif "rust" in content and "🦀" in block.get("content", ""):
                    rust_idx = i
                elif "bash" in content:
                    bash_idx = i

        # Check 1: Rust section exists with correct emoji
        if rust_idx is None:
            errors.append("[X] heading_2 '🦀 Rust Examples' not found")
        else:
            checks_passed.append("[C] Rust Examples heading_2 found with 🦀 emoji")

        # Check 2: Rust is after Typescript
        if typescript_idx is not None:
            if rust_idx <= typescript_idx:
                errors.append(f"[X] Rust section (pos {rust_idx}) must be after Typescript (pos {typescript_idx})")
            else:
                checks_passed.append("[C] Rust section positioned after Typescript")

        # Check 3: First Rust code block with iterator content
        first_rust_code_found = False
        first_code_idx = None
        for i in range(rust_idx + 1, min(rust_idx + 15, len(sorted_blocks))):
            block = sorted_blocks[i]
            if block.get("type") in ["heading2", "heading_2"]:
                break
            if block.get("type") == "code":
                properties = block.get("properties", {})
                language = properties.get("language", block.get("language", ""))
                content = block.get("content", "")
            
                if "rust" in language.lower():
                    # Check for iterator pattern content
                    required_terms = ["vec!", "iter", "map", "collect", "doubled"]
                    found_terms = sum(1 for term in required_terms if term.lower() in content.lower())
                    if found_terms >= 3:
                        first_rust_code_found = True
                        first_code_idx = i
                        checks_passed.append("[C] First Rust code block with iterator patterns found")
                        break

        if not first_rust_code_found:
            errors.append("[X] Code block with language 'rust' and iterator/map/collect content not found")
        else:
            checks_passed.append("[C] Code block with language 'rust' and iterator/map/collect content found")

        # Check 4: First description paragraph about iterator patterns
        first_paragraph_found = False
        for i in range(first_code_idx + 1 if first_code_idx else rust_idx + 1, min(rust_idx + 15, len(sorted_blocks))):
            block = sorted_blocks[i]
            if block.get("type") in ["heading2", "heading_2"]:
                break
            if block.get("type") in ["paragraph", "text"]:
                content = block.get("content", "").lower()
                if "iterator" in content and ("functional" in content or "pattern" in content):
                    first_paragraph_found = True
                    checks_passed.append("[C] Iterator pattern description paragraph found")
                    break

        if not first_paragraph_found:
            errors.append("[X] Paragraph describing iterator patterns and functional programming not found")
        else:
            checks_passed.append("[C] Paragraph describing iterator patterns and functional programming found")

        # Check 5: Second Rust code block with concurrent/thread content
        second_rust_code_found = False
        for i in range(rust_idx + 1, min(rust_idx + 20, len(sorted_blocks))):
            block = sorted_blocks[i]
            if block.get("type") in ["heading2", "heading_2"]:
                break
            if block.get("type") == "code":
                properties = block.get("properties", {})
                language = properties.get("language", block.get("language", ""))
                content = block.get("content", "")
            
                if "rust" in language.lower():
                    # Check for concurrent programming content
                    concurrent_terms = ["thread", "mpsc", "channel", "spawn", "send", "recv"]
                    found_terms = sum(1 for term in concurrent_terms if term.lower() in content.lower())
                    if found_terms >= 3:
                        second_rust_code_found = True
                        checks_passed.append("[C] Second Rust code block with concurrent programming found")
                        break

        if not second_rust_code_found:
            errors.append("[X] Code block with language 'rust' and concurrent/thread/mpsc content not found")
        else:
            checks_passed.append("[C] Code block with language 'rust' and concurrent/thread/mpsc content found")

        # Check 6: Second description paragraph about thread communication
        second_paragraph_found = False
        for i in range(rust_idx + 1, min(rust_idx + 20, len(sorted_blocks))):
            block = sorted_blocks[i]
            if block.get("type") in ["heading2", "heading_2"]:
                break
            if block.get("type") in ["paragraph", "text"]:
                content = block.get("content", "").lower()
                if "concurrent" in content or ("thread" in content and "communication" in content) or "channel" in content:
                    second_paragraph_found = True
                    checks_passed.append("[C] Concurrent programming description paragraph found")
                    break

        if not second_paragraph_found:
            errors.append("[X] Paragraph describing concurrent programming/thread communication not found")
        else:
            checks_passed.append("[C] Paragraph describing concurrent programming/thread communication found")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: Code Examples Ruby Section
# =============================================================================
def _validate_code_examples_ruby_section(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Code Examples Repository with new Ruby Examples section between Python and Typescript."""
    errors: list[str] = []

    checks_passed = []

    # Find Code Examples Repository page
    try:
        code_examples = _find_page_by_title(final_state_backend, "Code Examples Repository")
        if not code_examples:
            errors.append("[X] Code Examples Repository page not found")
        else:
            checks_passed.append("[C] Code Examples Repository page found")

        page_id = code_examples.get("_id")
        page_blocks = _get_blocks_for_page(final_state_backend, page_id)
        sorted_blocks = sorted(page_blocks, key=lambda b: b.get("order", 0))
        checks_passed.append("[C] Code Examples Repository page found")

        # Find section headings
        python_idx = None
        ruby_idx = None
        typescript_idx = None

        for i, block in enumerate(sorted_blocks):
            if block.get("type") in ["heading2", "heading_2"]:
                content = block.get("content", "").lower()
                if "python" in content:
                    python_idx = i
                elif "ruby" in content:
                    ruby_idx = i
                elif "typescript" in content:
                    typescript_idx = i

        # Check 1: Ruby section exists
        if ruby_idx is None:
            errors.append("[X] heading_2 'Ruby Examples' not found")
        else:
            checks_passed.append("[C] Ruby Examples heading_2 found")

        # Check 2: Ruby is between Python and Typescript
        if python_idx is not None and typescript_idx is not None:
            if not (python_idx < ruby_idx < typescript_idx):
                errors.append(f"[X] Ruby section (pos {ruby_idx}) must be between Python (pos {python_idx}) and Typescript (pos {typescript_idx})")
            else:
                checks_passed.append("[C] Ruby section positioned correctly between Python and Typescript")
        elif python_idx is not None:
            if ruby_idx <= python_idx:
                errors.append("[X] Ruby section should come after Python section")
            else:
                checks_passed.append("[C] Ruby section positioned after Python")
        elif typescript_idx is not None:
            if ruby_idx >= typescript_idx:
                errors.append("[X] Ruby section should come before Typescript section")
            else:
                checks_passed.append("[C] Ruby section positioned before Typescript")

        # Check 3: Ruby code block with User class content
        ruby_code_found = False
        code_block_idx = None
        for i in range(ruby_idx + 1, min(ruby_idx + 10, len(sorted_blocks))):
            block = sorted_blocks[i]
            if block.get("type") in ["heading2", "heading_2"]:
                break
            if block.get("type") == "code":
                properties = block.get("properties", {})
                language = properties.get("language", block.get("language", ""))
                content = block.get("content", "")
            
                if "ruby" in language.lower():
                    # Check for User class content
                    required_terms = ["class User", "attr_accessor", "initialize", "def display_info", "@name", "@email"]
                    found_terms = sum(1 for term in required_terms if term in content)
                    if found_terms >= 4:
                        ruby_code_found = True
                        code_block_idx = i
                        checks_passed.append("[C] Ruby code block with User class found")
                        break

        if not ruby_code_found:
            errors.append("[X] Code block with language 'ruby' and User class content not found")
        else:
            checks_passed.append("[C] Code block with language 'ruby' and User class content found")

        # Check 4: Description paragraph
        desc_paragraph_found = False
        paragraph_idx = None
        for i in range(ruby_idx + 1, min(ruby_idx + 10, len(sorted_blocks))):
            block = sorted_blocks[i]
            if block.get("type") in ["heading2", "heading_2"]:
                break
            if block.get("type") in ["paragraph", "text"]:
                content = block.get("content", "").lower()
                if "common ruby pattern" in content and "production code" in content:
                    desc_paragraph_found = True
                    paragraph_idx = i
                    checks_passed.append("[C] Description paragraph found")
                    break

        if not desc_paragraph_found:
            errors.append("[X] Paragraph 'Common ruby pattern for production code.' not found")
        else:
            checks_passed.append("[C] Paragraph 'Common ruby pattern for production code.' found")

        # Check 5: Image block exists in Ruby section
        image_found = False
        for i in range(ruby_idx + 1, min(ruby_idx + 15, len(sorted_blocks))):
            block = sorted_blocks[i]
            if block.get("type") in ["heading2", "heading_2"]:
                break
            if block.get("type") == "image":
                # Check that image has a URL
                properties = block.get("properties", {})
                url = properties.get("url", block.get("url", ""))
                if url:
                    image_found = True
                    checks_passed.append("[C] Image block found in Ruby section")
                    break

        if not image_found:
            errors.append("[X] Image block not found in Ruby section")
        else:
            checks_passed.append("[C] Image block found in Ruby section")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: Team Directory New Member
# =============================================================================
def _validate_team_directory_new_member(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Team Directory with new member, divider, callout, and updated description."""
    errors: list[str] = []

    checks_passed = []

    # Find Team Directory page
    try:
        team_directory = _find_page_by_title(final_state_backend, "Team Directory")
        if not team_directory:
            errors.append("[X] Team Directory page not found")
        else:
            checks_passed.append("[C] Team Directory page found")

        page_id = team_directory.get("_id")
        page_blocks = _get_blocks_for_page(final_state_backend, page_id)
        sorted_blocks = sorted(page_blocks, key=lambda b: b.get("order", 0))
        checks_passed.append("[C] Team Directory page found")

        # Find key positions
        design_team_idx = None
        engineering_team_idx = None
        carol_idx = None
        frank_idx = None
        image_idx = None
        sarah_idx = None

        for i, block in enumerate(sorted_blocks):
            block_type = block.get("type", "")
            content = block.get("content", "").lower()
        
            if block_type in ["heading2", "heading_2"]:
                if "design team" in content:
                    design_team_idx = i
                elif "engineering team" in content:
                    engineering_team_idx = i
            elif block_type in ["bulletedList", "bulleted_list", "bulleted_list_item"]:
                if "carol williams" in content:
                    carol_idx = i
                elif "frank zhang" in content:
                    frank_idx = i
                elif "sarah johnson" in content:
                    sarah_idx = i
            elif block_type == "image":
                if "team photo" in content.lower() or i > (design_team_idx or 0):
                    image_idx = i

        # Check 1: Sarah Johnson exists as bulletedList
        if sarah_idx is None:
            errors.append("[X] Sarah Johnson - UX Researcher bulletedList entry not found")
        else:
            checks_passed.append("[C] Sarah Johnson entry found")

        # Check 2: Sarah is after Carol (last Design Team member) and before image
        if carol_idx is not None and image_idx is not None:
            if not (carol_idx < sarah_idx < image_idx):
                errors.append(f"[X] Sarah Johnson (pos {sarah_idx}) should be after Carol Williams (pos {carol_idx}) and before Team Photo image (pos {image_idx})")
            else:
                checks_passed.append("[C] Sarah Johnson positioned correctly in Design Team")

        # Check 3: Divider after Frank Zhang in Engineering Team
        divider_after_frank = False
        if frank_idx is not None:
            for i in range(frank_idx + 1, min(frank_idx + 5, len(sorted_blocks))):
                if sorted_blocks[i].get("type") == "divider":
                    divider_after_frank = True
                    break

        if not divider_after_frank:
            errors.append("[X] Divider not found after Frank Zhang in Engineering Team")
        else:
            checks_passed.append("[C] Divider found after Frank Zhang")

        # Check 4: Yellow callout with 🆕 icon and Q1 2024 text after divider
        callout_found = False
        for i, block in enumerate(sorted_blocks):
            if block.get("type") == "callout":
                properties = block.get("properties", {})
                bg_color = properties.get("backgroundColor", block.get("backgroundColor", ""))
                icon = properties.get("icon", block.get("icon", ""))
                content = block.get("content", "")
            
                has_yellow_bg = "yellow" in bg_color.lower() if bg_color else False
                has_new_icon = "🆕" in icon if icon else False
                has_q1_text = "q1 2024" in content.lower() and "new team member" in content.lower()
            
                if has_yellow_bg and has_new_icon and has_q1_text:
                    callout_found = True
                    checks_passed.append("[C] Yellow callout with 🆕 icon and Q1 2024 text found")
                    break

        if not callout_found:
            errors.append("[X] Yellow callout with 🆕 icon and 'New team members joining in Q1 2024' not found")
        else:
            checks_passed.append("[C] Yellow callout with 🆕 icon and 'New team members joining in Q1 2024' found")

        # Check 5: Updated page description mentioning 20 individuals
        description_updated = False
        for block in sorted_blocks:
            if block.get("type") in ["paragraph", "text"]:
                content = block.get("content", "").lower()
                if "20" in content and ("talented" in content or "individuals" in content) and "acme" in content:
                    description_updated = True
                    checks_passed.append("[C] Page description updated with 20 individuals")
                    break

        if not description_updated:
            errors.append("[X] Page description not updated with text about 20 talented individuals")
        else:
            checks_passed.append("[C] Page description updated with text about 20 talented individuals")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: Project Documentation Reorganization
# =============================================================================
def _validate_project_documentation_reorganization(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Project Documentation reorganization with Legacy Documentation sub-page and content."""
    errors: list[str] = []

    checks_passed = []

    # Find Project Documentation page
    try:
        project_doc = _find_page_by_title(final_state_backend, "Project Documentation")
        if not project_doc:
            errors.append("[X] Project Documentation page not found")
        else:
            checks_passed.append("[C] Project Documentation page found")
    
        project_doc_id = project_doc.get("_id")
        checks_passed.append("[C] Project Documentation page found")

        # Check 1: Legacy Documentation page exists as child of Project Documentation
        legacy_doc = None
        child_pages = _get_child_pages(final_state_backend, project_doc_id)
        for child in child_pages:
            if "legacy documentation" in child.get("title", "").lower():
                legacy_doc = child
                break

        if not legacy_doc:
            errors.append("[X] Legacy Documentation page not found under Project Documentation")
        else:
            checks_passed.append("[C] Legacy Documentation page created under Project Documentation")

        # Check 2: Architecture page is now under Legacy Documentation
        legacy_doc_id = legacy_doc.get("_id")
        architecture_page = None
        legacy_children = _get_child_pages(final_state_backend, legacy_doc_id)
        for child in legacy_children:
            if "architecture" in child.get("title", "").lower():
                architecture_page = child
                break

        if not architecture_page:
            errors.append("[X] Architecture page not found under Legacy Documentation")
        else:
            checks_passed.append("[C] Architecture page moved under Legacy Documentation")

        # Check 3: Frontend and Backend Architecture are still under Architecture
        arch_id = architecture_page.get("_id")
        arch_children = _get_child_pages(final_state_backend, arch_id)
        arch_child_titles = [c.get("title", "").lower() for c in arch_children]
    
        has_frontend = any("frontend" in t for t in arch_child_titles)
        has_backend = any("backend" in t for t in arch_child_titles)
    
        if not (has_frontend and has_backend):
            errors.append("[X] Frontend/Backend Architecture sub-pages not preserved under Architecture")
        else:
            checks_passed.append("[C] Frontend/Backend Architecture sub-pages preserved")

        # Check 4: Project Documentation page has new content
        page_blocks = _get_blocks_for_page(final_state_backend, project_doc_id)
        sorted_blocks = sorted(page_blocks, key=lambda b: b.get("order", 0))

        # Check for heading_1 with Hub
        hub_heading_found = False
        for block in sorted_blocks:
            if block.get("type") in ["heading1", "heading_1"]:
                content = block.get("content", "")
                if "project documentation hub" in content.lower() and "📚" in content:
                    hub_heading_found = True
                    break

        if not hub_heading_found:
            errors.append("[X] heading_1 '📚 Project Documentation Hub' not found")
        else:
            checks_passed.append("[C] Project Documentation Hub heading found")

        # Check for heading_2 Documentation Structure
        structure_heading_found = False
        for block in sorted_blocks:
            if block.get("type") in ["heading2", "heading_2"]:
                content = block.get("content", "")
                if "documentation structure" in content.lower() and "📂" in content:
                    structure_heading_found = True
                    break

        if not structure_heading_found:
            errors.append("[X] heading_2 '📂 Documentation Structure' not found")
        else:
            checks_passed.append("[C] Documentation Structure heading found")

        # Check for numbered list items
        numbered_items = [b for b in sorted_blocks if b.get("type") in ["numberedList", "numbered_list", "numbered_list_item", "numbered"]]
        if len(numbered_items) < 3:
            errors.append(f"[X] Expected at least 3 numbered list items, found {len(numbered_items)}")
        else:
            checks_passed.append(f"[C] Found {len(numbered_items)} numbered list items")

        # Check for blue callout with tip
        tip_callout_found = False
        for block in sorted_blocks:
            if block.get("type") == "callout":
                properties = block.get("properties", {})
                bg_color = properties.get("backgroundColor", block.get("backgroundColor", ""))
                icon = properties.get("icon", block.get("icon", ""))
                content = block.get("content", "").lower()
            
                has_blue_bg = "blue" in bg_color.lower() if bg_color else False
                has_bulb_icon = "💡" in icon if icon else False
                has_tip_text = "tip" in content and ("cmd" in content or "ctrl" in content) and "search" in content
            
                if has_blue_bg and has_bulb_icon and has_tip_text:
                    tip_callout_found = True
                    break

        if not tip_callout_found:
            errors.append("[X] Blue callout with 💡 icon and search tip not found")
        else:
            checks_passed.append("[C] Blue tip callout found")

        # Check 5: Page is favorited
        if not project_doc.get("isFavorite", False):
            errors.append("[X] Project Documentation page not marked as favorite")
        else:
            checks_passed.append("[C] Project Documentation marked as favorite")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: External Resources Categorization
# =============================================================================
def _validate_external_resources_categorization(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate External Resources page with categorized bookmarks."""
    errors: list[str] = []

    checks_passed = []

    # Find External Resources page
    try:
        ext_resources = _find_page_by_title(final_state_backend, "External Resources & Links")
        if not ext_resources:
            ext_resources = _find_page_by_title(final_state_backend, "External Resources")
        if not ext_resources:
            errors.append("[X] External Resources page not found")
        else:
            checks_passed.append("[C] External Resources page found")

        page_id = ext_resources.get("_id")
        page_blocks = _get_blocks_for_page(final_state_backend, page_id)
        sorted_blocks = sorted(page_blocks, key=lambda b: b.get("order", 0))
        checks_passed.append("[C] External Resources page found")

        # Find category headings
        categories = {
            "development tools": {"emoji": "🛠️", "idx": None},
            "documentation": {"emoji": "📚", "idx": None},
            "learning resources": {"emoji": "🎓", "idx": None},
            "other resources": {"emoji": "🔗", "idx": None},
        }

        for i, block in enumerate(sorted_blocks):
            if block.get("type") in ["heading2", "heading_2"]:
                content = block.get("content", "").lower()
                for cat_name, cat_info in categories.items():
                    if cat_name in content:
                        cat_info["idx"] = i
                        break

        # Check 1: All category headings exist
        missing_categories = [name for name, info in categories.items() if info["idx"] is None]
        if missing_categories:
            errors.append(f"[X] Missing category headings: {', '.join(missing_categories)}")
        else:
            checks_passed.append("[C] All 4 category headings found")

        # Check 2: Categories are in correct order
        indices = [(name, info["idx"]) for name, info in categories.items()]
        sorted_indices = sorted(indices, key=lambda x: x[1])
        expected_order = ["development tools", "documentation", "learning resources", "other resources"]
    
        # Just verify they exist, order can be flexible based on implementation
        checks_passed.append("[C] Category headings organized")

        # Check 3: Resource Summary section exists at top
        summary_found = False
        for i, block in enumerate(sorted_blocks[:10]):
            if block.get("type") in ["heading2", "heading_2"]:
                content = block.get("content", "")
                if "resource summary" in content.lower() and "📊" in content:
                    summary_found = True
                    break

        if not summary_found:
            errors.append("[X] Resource Summary heading not found near top of page")
        else:
            checks_passed.append("[C] Resource Summary heading found at top")

        # Check 4: Summary text mentions total resources and categories
        summary_text_found = False
        for block in sorted_blocks[:15]:
            if block.get("type") in ["paragraph", "text"]:
                content = block.get("content", "").lower()
                if "total" in content and "resource" in content and "categor" in content:
                    summary_text_found = True
                    break

        if not summary_text_found:
            errors.append("[X] Summary paragraph with total resources and categories count not found")
        else:
            checks_passed.append("[C] Summary text with resource counts found")

        # Check 5: Each category has a "Contains X resources" paragraph
        contains_paragraphs = 0
        for block in sorted_blocks:
            if block.get("type") in ["paragraph", "text"]:
                content = block.get("content", "").lower()
                if "contains" in content and "resource" in content:
                    contains_paragraphs += 1

        if contains_paragraphs < 2:
            errors.append(f"[X] Expected resource count paragraphs for categories, found {contains_paragraphs}")
        else:
            checks_passed.append(f"[C] Found {contains_paragraphs} category resource count paragraphs")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: Bug Tracker Mobile Priority
# =============================================================================
def _validate_bug_tracker_mobile_priority(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Bug Tracker with mobile priority callouts and analysis summary."""
    errors: list[str] = []

    checks_passed = []

    # Find Bug Tracker page
    try:
        bug_tracker = _find_page_by_title(final_state_backend, "Bug Tracker")
        if not bug_tracker:
            errors.append("[X] Bug Tracker page not found")
        else:
            checks_passed.append("[C] Bug Tracker page found")

        page_id = bug_tracker.get("_id")
        page_blocks = _get_blocks_for_page(final_state_backend, page_id)
        sorted_blocks = sorted(page_blocks, key=lambda b: b.get("order", 0))
        checks_passed.append("[C] Bug Tracker page found")

        # Count todos for statistics
        all_todos = [b for b in sorted_blocks if b.get("type") in ["todo", "to_do", "checkbox"]]
        checked_todos = [t for t in all_todos if t.get("properties", {}).get("checked", False) or t.get("checked", False)]
        unchecked_todos = [t for t in all_todos if not (t.get("properties", {}).get("checked", False) or t.get("checked", False))]
    
        # Find mobile/offline related unchecked todos
        mobile_offline_todos = []
        for todo in unchecked_todos:
            content = todo.get("content", "").lower()
            if "mobile" in content or "offline" in content:
                mobile_offline_todos.append(todo)

        # Check 1: Orange callouts with 📱 icon exist (for mobile priority issues)
        mobile_callouts = []
        for block in sorted_blocks:
            if block.get("type") == "callout":
                properties = block.get("properties", {})
                bg_color = properties.get("backgroundColor", block.get("backgroundColor", ""))
                icon = properties.get("icon", block.get("icon", ""))
                content = block.get("content", "").lower()
            
                has_orange_bg = "orange" in bg_color.lower() if bg_color else False
                has_mobile_icon = "📱" in icon if icon else False
                has_mobile_text = "mobile priority" in content
            
                if has_orange_bg and has_mobile_icon and has_mobile_text:
                    mobile_callouts.append(block)

        # We expect at least some mobile callouts if there are mobile/offline todos
        if len(mobile_offline_todos) > 0 and len(mobile_callouts) == 0:
            errors.append(f"[X] Expected mobile priority callouts for {len(mobile_offline_todos)} mobile/offline todos, found none")
        else:
            checks_passed.append(f"[C] Expected mobile priority callouts for {len(mobile_offline_todos)} mobile/offline todos, found none")
        if len(mobile_callouts) > 0:
            checks_passed.append(f"[C] Found {len(mobile_callouts)} mobile priority callouts")

        # Check 2: Bug Analysis Summary heading exists
        summary_heading_found = False
        low_priority_idx = None
    
        for i, block in enumerate(sorted_blocks):
            if block.get("type") in ["heading2", "heading_2"]:
                content = block.get("content", "").lower()
                if "low priority" in content:
                    low_priority_idx = i
            elif block.get("type") in ["heading3", "heading_3"]:
                content = block.get("content", "")
                if "bug analysis summary" in content.lower() and "📊" in content:
                    summary_heading_found = True

        if not summary_heading_found:
            errors.append("[X] heading_3 '📊 Bug Analysis Summary' not found")
        else:
            checks_passed.append("[C] Bug Analysis Summary heading found")

        # Check 3: Numbered list with statistics
        numbered_items = [b for b in sorted_blocks if b.get("type") in ["numberedList", "numbered_list", "numbered_list_item", "numbered"]]
        stats_items_found = 0
        for item in numbered_items:
            content = item.get("content", "").lower()
            if "total open bugs" in content or "mobile-related" in content or "critical" in content or "resolution rate" in content:
                stats_items_found += 1

        if stats_items_found < 3:
            errors.append(f"[X] Expected at least 3 statistics items in numbered list, found {stats_items_found}")
        else:
            checks_passed.append(f"[C] Found {stats_items_found} statistics items")

        # Check 4: Conditional callout based on resolution rate (green or red)
        resolution_callout_found = False
        total_todos = len(all_todos)
        checked_count = len(checked_todos)
        resolution_rate = (checked_count / total_todos * 100) if total_todos > 0 else 0
    
        for block in sorted_blocks:
            if block.get("type") == "callout":
                properties = block.get("properties", {})
                bg_color = properties.get("backgroundColor", block.get("backgroundColor", ""))
                content = block.get("content", "")
            
                has_green = "green" in bg_color.lower() if bg_color else False
                has_red = "red" in bg_color.lower() if bg_color else False
                has_progress_text = "progress" in content.lower() or "great" in content.lower()
                has_attention_text = "attention" in content.lower() or "backlog" in content.lower()
            
                if (has_green and has_progress_text) or (has_red and has_attention_text):
                    resolution_callout_found = True
                    checks_passed.append(f"[C] Conditional callout found (resolution rate: {resolution_rate:.1f}%)")
                    break

        if not resolution_callout_found:
            errors.append("[X] Conditional callout for resolution rate (green/red) not found")
        else:
            checks_passed.append("[C] Conditional callout for resolution rate (green/red) found")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: Feature Requests Pending Review
# =============================================================================
def _validate_feature_requests_pending_review(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Feature Requests with pending review callouts and Community Wishlist updates."""
    errors: list[str] = []

    checks_passed = []

    # Find Feature Requests page
    try:
        feature_requests = _find_page_by_title(final_state_backend, "Feature Requests")
        if not feature_requests:
            errors.append("[X] Feature Requests page not found")
        else:
            checks_passed.append("[C] Feature Requests page found")

        page_id = feature_requests.get("_id")
        page_blocks = _get_blocks_for_page(final_state_backend, page_id)
        sorted_blocks = sorted(page_blocks, key=lambda b: b.get("order", 0))
        checks_passed.append("[C] Feature Requests page found")

        # Check 1: Gray callouts with 🕐 icon for pending review
        pending_callouts = []
        for block in sorted_blocks:
            if block.get("type") == "callout":
                properties = block.get("properties", {})
                bg_color = properties.get("backgroundColor", block.get("backgroundColor", ""))
                icon = properties.get("icon", block.get("icon", ""))
                content = block.get("content", "").lower()
            
                has_gray_bg = "gray" in bg_color.lower() if bg_color else False
                has_clock_icon = "🕐" in icon if icon else False
                has_pending_text = "pending review" in content or "status: pending" in content
            
                if has_gray_bg and has_clock_icon and has_pending_text:
                    pending_callouts.append(block)

        if len(pending_callouts) == 0:
            errors.append("[X] No gray callouts with 🕐 icon and pending review text found")
        else:
            checks_passed.append(f"[C] Found {len(pending_callouts)} pending review callouts")

        # Check 2: Community Wishlist heading (renamed from Community Suggestions)
        wishlist_found = False
        for block in sorted_blocks:
            if block.get("type") in ["heading2", "heading_2"]:
                content = block.get("content", "")
                if "community wishlist" in content.lower() and "💡" in content:
                    wishlist_found = True
                    break

        if not wishlist_found:
            errors.append("[X] heading_2 '💡 Community Wishlist' not found (should be renamed from Community Suggestions)")
        else:
            checks_passed.append("[C] Community Wishlist heading found")

        # Check 3: Numbered list items exist (converted from bullets)
        numbered_items = [b for b in sorted_blocks if b.get("type") in ["numberedList", "numbered_list", "numbered_list_item", "numbered"]]
    
        # Check for expected content that was originally in bullets
        expected_content = ["slack", "version history", "search filter", "ai-powered"]
        found_content = 0
        for item in numbered_items:
            content = item.get("content", "").lower()
            for expected in expected_content:
                if expected in content:
                    found_content += 1
                    break

        if found_content < 3:
            errors.append(f"[X] Expected numbered list with converted bullet content, found {found_content} matching items")
        else:
            checks_passed.append(f"[C] Found {len(numbered_items)} numbered list items including converted content")

        # Check 4: AI-powered content suggestions item
        ai_item_found = False
        for item in numbered_items:
            content = item.get("content", "").lower()
            if "ai-powered" in content and "content suggestion" in content:
                ai_item_found = True
                break

        if not ai_item_found:
            errors.append("[X] Numbered list item 'AI-powered content suggestions' not found")
        else:
            checks_passed.append("[C] AI-powered content suggestions item found")

        # Check 5: Implementation Timeline heading at end
        timeline_found = False
        for block in sorted_blocks[-15:]:
            if block.get("type") in ["heading2", "heading_2"]:
                content = block.get("content", "")
                if "implementation timeline" in content.lower() and "📅" in content:
                    timeline_found = True
                    break

        if not timeline_found:
            errors.append("[X] heading_2 '📅 Implementation Timeline' not found at end of page")
        else:
            checks_passed.append("[C] Implementation Timeline heading found at end")

        # Check 6: Timeline paragraph with Q2/Q3 2024
        timeline_paragraph_found = False
        for block in sorted_blocks[-10:]:
            if block.get("type") in ["paragraph", "text"]:
                content = block.get("content", "").lower()
                if "q2 2024" in content and "q3 2024" in content:
                    timeline_paragraph_found = True
                    break

        if not timeline_paragraph_found:
            errors.append("[X] Timeline paragraph mentioning Q2 2024 and Q3 2024 not found")
        else:
            checks_passed.append("[C] Timeline paragraph found")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: Team Directory Image Reorganization
# =============================================================================
def _validate_team_directory_image_reorg(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Team Directory with image at top, Team Structure section, and member count callouts."""
    errors: list[str] = []

    checks_passed = []

    # Find Team Directory page
    try:
        team_directory = _find_page_by_title(final_state_backend, "Team Directory")
        if not team_directory:
            errors.append("[X] Team Directory page not found")
        else:
            checks_passed.append("[C] Team Directory page found")

        page_id = team_directory.get("_id")
        page_blocks = _get_blocks_for_page(final_state_backend, page_id)
        sorted_blocks = sorted(page_blocks, key=lambda b: b.get("order", 0))
        checks_passed.append("[C] Team Directory page found")

        # Check 1: Image at top (position 0 or near top)
        image_block = None
        image_idx = None
        for i, block in enumerate(sorted_blocks[:5]):
            if block.get("type") == "image":
                image_block = block
                image_idx = i
                break

        if image_block is None:
            errors.append("[X] Team Photo image not found at top of page")
        else:
            checks_passed.append("[C] Team Photo image found at top")

        # Check 2: Image has caption with "Acme Corp Team"
        properties = image_block.get("properties", {})
        caption = properties.get("caption", image_block.get("caption", ""))
        content = image_block.get("content", "")
    
        has_caption = ("acme" in caption.lower() and "2024" in caption.lower()) or \
                      ("acme" in content.lower() and "2024" in content.lower())
        if not has_caption:
            errors.append("[X] Image caption 'Acme Corp Team - January 2024 All Hands' not found")
        else:
            checks_passed.append("[C] Image caption with Acme Corp Team found")

        # Check 3: Team Structure heading
        team_structure_found = False
        for block in sorted_blocks:
            if block.get("type") in ["heading2", "heading_2"]:
                content = block.get("content", "")
                if "team structure" in content.lower() and "👥" in content:
                    team_structure_found = True
                    break

        if not team_structure_found:
            errors.append("[X] heading_2 '👥 Team Structure' not found")
        else:
            checks_passed.append("[C] Team Structure heading found")

        # Check 4: Three team heading3 blocks
        team_headings = {
            "engineering": {"emoji": "🚀", "found": False},
            "design": {"emoji": "🎨", "found": False},
            "business": {"emoji": "💼", "found": False},
        }

        for block in sorted_blocks:
            if block.get("type") in ["heading3", "heading_3"]:
                content = block.get("content", "").lower()
                original_content = block.get("content", "")
                for team, info in team_headings.items():
                    if team in content and info["emoji"] in original_content:
                        info["found"] = True

        missing_teams = [team for team, info in team_headings.items() if not info["found"]]
        if missing_teams:
            errors.append(f"[X] Missing team headings: {', '.join(missing_teams)}")
        else:
            checks_passed.append("[C] All three team headings found")

        # Check 5: Three colored callouts with member counts
        callout_colors = {"blue": False, "green": False, "yellow": False}
    
        for block in sorted_blocks:
            if block.get("type") == "callout":
                properties = block.get("properties", {})
                bg_color = properties.get("backgroundColor", block.get("backgroundColor", ""))
                content = block.get("content", "").lower()
            
                has_members = "member" in content
                if has_members:
                    if "blue" in bg_color.lower():
                        callout_colors["blue"] = True
                    elif "green" in bg_color.lower():
                        callout_colors["green"] = True
                    elif "yellow" in bg_color.lower():
                        callout_colors["yellow"] = True

        missing_callouts = [color for color, found in callout_colors.items() if not found]
        if missing_callouts:
            errors.append(f"[X] Missing colored callouts with member counts: {', '.join(missing_callouts)}")
        else:
            checks_passed.append("[C] All three colored callouts with member counts found")

        # Check 6: Summary paragraph with 19 members
        summary_found = False
        for block in sorted_blocks[-10:]:
            if block.get("type") in ["paragraph", "text"]:
                content = block.get("content", "").lower()
                if "19" in content and "member" in content and ("department" in content or "team" in content):
                    summary_found = True
                    break

        if not summary_found:
            errors.append("[X] Summary paragraph with '19 members across 3 departments' not found")
        else:
            checks_passed.append("[C] Summary paragraph found")

        # Check 7: Divider before summary
        divider_found = False
        for block in sorted_blocks[-15:]:
            if block.get("type") == "divider":
                divider_found = True
                break

        if not divider_found:
            errors.append("[X] Divider before summary not found")
        else:
            checks_passed.append("[C] Divider before summary found")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: Workspace Intelligence Report
# =============================================================================
def _validate_workspace_intelligence_report(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Workspace Intelligence Report with cross-page analysis."""
    errors: list[str] = []

    checks_passed = []

    # Find Workspace Intelligence Report page
    try:
        report_page = _find_page_by_title(final_state_backend, "Workspace Intelligence Report")
        if not report_page:
            errors.append("[X] Workspace Intelligence Report page not found")
        else:
            checks_passed.append("[C] Workspace Intelligence Report page found")

        page_id = report_page.get("_id")
        page_blocks = _get_blocks_for_page(final_state_backend, page_id)
        sorted_blocks = sorted(page_blocks, key=lambda b: b.get("order", 0))
        checks_passed.append("[C] Workspace Intelligence Report page found")

        # Check 1: Main heading
        main_heading_found = False
        for block in sorted_blocks:
            if block.get("type") in ["heading1", "heading_1"]:
                content = block.get("content", "")
                if "workspace intelligence report" in content.lower() and "🧠" in content:
                    main_heading_found = True
                    break

        if not main_heading_found:
            errors.append("[X] heading_1 '🧠 Workspace Intelligence Report' not found")
        else:
            checks_passed.append("[C] Main heading found")

        # Check 2: Report Generated heading
        report_generated_found = False
        for block in sorted_blocks:
            if block.get("type") in ["heading2", "heading_2"]:
                content = block.get("content", "")
                if "report generated" in content.lower() and "📅" in content:
                    report_generated_found = True
                    break

        if not report_generated_found:
            errors.append("[X] heading_2 '📅 Report Generated' not found")
        else:
            checks_passed.append("[C] Report Generated heading found")

        # Check 3: Feature Request Pipeline heading and purple callout
        pipeline_found = False
        purple_callout_found = False
    
        for block in sorted_blocks:
            if block.get("type") in ["heading2", "heading_2"]:
                content = block.get("content", "")
                if "feature request pipeline" in content.lower() and "🎯" in content:
                    pipeline_found = True
            elif block.get("type") == "callout":
                properties = block.get("properties", {})
                bg_color = properties.get("backgroundColor", block.get("backgroundColor", ""))
                icon = properties.get("icon", block.get("icon", ""))
                content = block.get("content", "").lower()
            
                has_purple_bg = "purple" in bg_color.lower() if bg_color else False
                has_sparkle_icon = "✨" in icon if icon else False
                has_completion_rate = "completion rate" in content and "%" in content
            
                if has_purple_bg and has_sparkle_icon and has_completion_rate:
                    purple_callout_found = True

        if not pipeline_found:
            errors.append("[X] heading_2 '🎯 Feature Request Pipeline' not found")
        else:
            checks_passed.append("[C] Feature Request Pipeline heading found")

        if not purple_callout_found:
            errors.append("[X] Purple callout with completion rate not found")
        else:
            checks_passed.append("[C] Purple callout with feature completion rate found")

        # Check 4: Shipped Features and In Pipeline headings
        shipped_found = False
        pipeline_items_found = False
    
        for block in sorted_blocks:
            if block.get("type") in ["heading3", "heading_3"]:
                content = block.get("content", "")
                if "shipped features" in content.lower() and "✅" in content:
                    shipped_found = True
                elif "in pipeline" in content.lower() and "🚧" in content:
                    pipeline_items_found = True

        if not shipped_found:
            errors.append("[X] heading_3 '✅ Shipped Features' not found")
        else:
            checks_passed.append("[C] heading_3 '✅ Shipped Features' found")
        if not pipeline_items_found:
            errors.append("[X] heading_3 '🚧 In Pipeline' not found")
        else:
            checks_passed.append("[C] Shipped Features and In Pipeline headings found")

        # Check 5: Meeting Productivity Score heading
        productivity_found = False
        for block in sorted_blocks:
            if block.get("type") in ["heading2", "heading_2"]:
                content = block.get("content", "")
                if "meeting productivity" in content.lower() and "📊" in content:
                    productivity_found = True
                    break

        if not productivity_found:
            errors.append("[X] heading_2 '📊 Meeting Productivity Score' not found")
        else:
            checks_passed.append("[C] Meeting Productivity Score heading found")

        # Check 6: Project Goal Alignment heading and conditional callout
        goal_alignment_found = False
        goal_callout_found = False
    
        for block in sorted_blocks:
            if block.get("type") in ["heading2", "heading_2"]:
                content = block.get("content", "")
                if "project goal" in content.lower() or "goal alignment" in content.lower():
                    goal_alignment_found = True
            elif block.get("type") == "callout":
                properties = block.get("properties", {})
                bg_color = properties.get("backgroundColor", block.get("backgroundColor", ""))
                content = block.get("content", "").lower()
            
                # Should be green or yellow based on Q1 vs Q2 comparison
                has_comparison_color = "green" in bg_color.lower() or "yellow" in bg_color.lower() if bg_color else False
                has_comparison_text = "q1" in content or "q2" in content
            
                if has_comparison_color and has_comparison_text:
                    goal_callout_found = True

        if not goal_alignment_found:
            errors.append("[X] heading_2 for Project Goal Alignment not found")
        else:
            checks_passed.append("[C] Project Goal Alignment heading found")

        # Check 7: Insights heading with 3 bullet points
        insights_found = False
        insights_idx = None
    
        for i, block in enumerate(sorted_blocks):
            if block.get("type") in ["heading2", "heading_2"]:
                content = block.get("content", "")
                if "insights" in content.lower() and "💡" in content:
                    insights_found = True
                    insights_idx = i
                    break

        if not insights_found:
            errors.append("[X] heading_2 '💡 Insights' not found")
        else:
            checks_passed.append("[C] Insights heading found")

        # Count bullet points after Insights heading
        if insights_idx is not None:
            bullet_count = 0
            for i in range(insights_idx + 1, len(sorted_blocks)):
                block = sorted_blocks[i]
                if block.get("type") in ["heading2", "heading_2", "heading1", "heading_1"]:
                    break
                if block.get("type") in ["bulletedList", "bulleted_list", "bulleted_list_item"]:
                    bullet_count += 1

            if bullet_count < 3:
                errors.append(f"[X] Expected at least 3 bullet points under Insights, found {bullet_count}")
            else:
                checks_passed.append(f"[C] Found {bullet_count} insight bullet points")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: Documentation Audit Report
# =============================================================================
def _validate_documentation_audit_report(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Documentation Audit Report as sub-page of Project Documentation with hierarchy analysis and recommendations."""
    errors: list[str] = []

    checks_passed = []

    # Find Project Documentation page
    try:
        project_docs = _find_page_by_title(final_state_backend, "Project Documentation")
        if not project_docs:
            errors.append("[X] Project Documentation page not found")
        else:
            checks_passed.append("[C] Project Documentation page found")
    
        project_docs_id = project_docs.get("_id")
        checks_passed.append("[C] Project Documentation page found")

        # Find Documentation Audit Report as child of Project Documentation
        audit_report = _find_child_by_title_with_id(final_state_backend, project_docs_id, "documentation audit report")

        if not audit_report:
            errors.append("[X] Documentation Audit Report not found as child of Project Documentation")
        else:
            checks_passed.append("[C] Documentation Audit Report created as sub-page")

        page_id = audit_report.get("_id")
        page_blocks = _get_blocks_for_page(final_state_backend, page_id)
        sorted_blocks = sorted(page_blocks, key=lambda b: b.get("order", 0))

        # Check 1: Main heading with magnifying glass emoji
        main_heading_found = False
        for block in sorted_blocks:
            if block.get("type") in ["heading1", "heading_1"]:
                content = block.get("content", "")
                if "documentation audit report" in content.lower() and "🔍" in content:
                    main_heading_found = True
                    break

        if not main_heading_found:
            errors.append("[X] heading_1 '🔍 Documentation Audit Report' not found")
        else:
            checks_passed.append("[C] Main heading found")

        # Check 2: Page Hierarchy Analysis heading
        hierarchy_found = False
        for block in sorted_blocks:
            if block.get("type") in ["heading2", "heading_2"]:
                content = block.get("content", "")
                if "page hierarchy" in content.lower() and "📊" in content:
                    hierarchy_found = True
                    break

        if not hierarchy_found:
            errors.append("[X] heading_2 '📊 Page Hierarchy Analysis' not found")
        else:
            checks_passed.append("[C] Page Hierarchy Analysis heading found")

        # Check 3: Content Metrics heading
        metrics_found = False
        for block in sorted_blocks:
            if block.get("type") in ["heading2", "heading_2"]:
                content = block.get("content", "")
                if "content metrics" in content.lower() and "📈" in content:
                    metrics_found = True
                    break

        if not metrics_found:
            errors.append("[X] heading_2 '📈 Content Metrics' not found")
        else:
            checks_passed.append("[C] Content Metrics heading found")

        # Check 4: Recommendations heading
        recommendations_found = False
        for block in sorted_blocks:
            if block.get("type") in ["heading2", "heading_2"]:
                content = block.get("content", "")
                if "recommendations" in content.lower() and "🎯" in content:
                    recommendations_found = True
                    break

        if not recommendations_found:
            errors.append("[X] heading_2 '🎯 Recommendations' not found")
        else:
            checks_passed.append("[C] Recommendations heading found")

        # Check 5: Three callouts with specific colors
        callout_colors = {"orange": False, "blue": False, "green": False}
    
        for block in sorted_blocks:
            if block.get("type") == "callout":
                properties = block.get("properties", {})
                bg_color = properties.get("backgroundColor", block.get("backgroundColor", ""))
                content = block.get("content", "").lower()
            
                if "orange" in bg_color.lower():
                    if "<5 blocks" in content or "need more content" in content or "⚠️" in block.get("content", ""):
                        callout_colors["orange"] = True
                elif "blue" in bg_color.lower():
                    if "code examples" in content or "architecture" in content or "💡" in block.get("content", ""):
                        callout_colors["blue"] = True
                elif "green" in bg_color.lower():
                    if "component library" in content or "well documented" in content or "✅" in block.get("content", ""):
                        callout_colors["green"] = True

        missing_callouts = [color for color, found in callout_colors.items() if not found]
        if missing_callouts:
            errors.append(f"[X] Missing recommendation callouts with colors: {', '.join(missing_callouts)}")
        else:
            checks_passed.append("[C] All three colored callouts found with correct content")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: Team Organization Chart
# =============================================================================
def _validate_team_organization_chart(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Team Directory has organization chart with leadership, teams, and placeholder image."""
    errors: list[str] = []

    checks_passed = []

    # Find Team Directory page
    try:
        team_directory = _find_page_by_title(final_state_backend, "Team Directory")
        if not team_directory:
            errors.append("[X] Team Directory page not found")
        else:
            checks_passed.append("[C] Team Directory page found")

        page_id = team_directory.get("_id")
        page_blocks = _get_blocks_for_page(final_state_backend, page_id)
        sorted_blocks = sorted(page_blocks, key=lambda b: b.get("order", 0))
        checks_passed.append("[C] Team Directory page found")

        # Check 1: Team Organization Chart heading
        org_chart_found = False
        for block in sorted_blocks:
            if block.get("type") in ["heading2", "heading_2"]:
                content = block.get("content", "")
                if "team organization chart" in content.lower() and "🏢" in content:
                    org_chart_found = True
                    break

        if not org_chart_found:
            errors.append("[X] heading_2 '🏢 Team Organization Chart' not found")
        else:
            checks_passed.append("[C] Team Organization Chart heading found")

        # Check 2: Leadership heading
        leadership_found = False
        for block in sorted_blocks:
            if block.get("type") in ["heading3", "heading_3"]:
                content = block.get("content", "")
                if "leadership" in content.lower() and "👔" in content:
                    leadership_found = True
                    break

        if not leadership_found:
            errors.append("[X] heading_3 '👔 Leadership' not found")
        else:
            checks_passed.append("[C] Leadership heading found")

        # Check 3: CEO and CTO in bulleted list
        ceo_found = False
        cto_found = False
        for block in sorted_blocks:
            if block.get("type") in ["bulletedList", "bulleted_list", "bulleted_list_item"]:
                content = block.get("content", "").lower()
                if "ceo" in content:
                    ceo_found = True
                if "cto" in content:
                    cto_found = True

        if not ceo_found or not cto_found:
            errors.append(f"[X] Missing leadership roles: CEO found={ceo_found}, CTO found={cto_found}")
        else:
            checks_passed.append("[C] CEO and CTO entries found")

        # Check 4: Engineering Teams heading
        eng_teams_found = False
        for block in sorted_blocks:
            if block.get("type") in ["heading3", "heading_3"]:
                content = block.get("content", "")
                if "engineering teams" in content.lower() and "👥" in content:
                    eng_teams_found = True
                    break

        if not eng_teams_found:
            errors.append("[X] heading_3 '👥 Engineering Teams' not found")
        else:
            checks_passed.append("[C] Engineering Teams heading found")

        # Check 5: Frontend, Backend, DevOps teams in numbered list
        team_names = {"frontend": False, "backend": False, "devops": False}
        for block in sorted_blocks:
            if block.get("type") in ["numberedList", "numbered_list", "numbered_list_item", "numbered"]:
                content = block.get("content", "").lower()
                for team in team_names:
                    if team in content:
                        team_names[team] = True

        missing_teams = [team for team, found in team_names.items() if not found]
        if missing_teams:
            errors.append(f"[X] Missing team sections: {', '.join(missing_teams)}")
        else:
            checks_passed.append("[C] Frontend, Backend, DevOps teams found")

        # Check 6: Gray callout with team size
        team_size_callout_found = False
        for block in sorted_blocks:
            if block.get("type") == "callout":
                properties = block.get("properties", {})
                bg_color = properties.get("backgroundColor", block.get("backgroundColor", ""))
                icon = properties.get("icon", block.get("icon", ""))
                content = block.get("content", "").lower()
            
                if "gray" in bg_color.lower() and "📊" in icon and "total team size" in content:
                    team_size_callout_found = True
                    break

        if not team_size_callout_found:
            errors.append("[X] Gray callout with '📊' icon and 'Total team size' not found")
        else:
            checks_passed.append("[C] Team size callout found")

        # Check 7: Placeholder image at end
        image_found = False
        for block in sorted_blocks[-10:]:
            if block.get("type") == "image":
                properties = block.get("properties", {})
                url = properties.get("url", block.get("url", block.get("content", "")))
                if "placeholder" in url.lower() or "via.placeholder" in url.lower():
                    image_found = True
                    break

        if not image_found:
            errors.append("[X] Placeholder image not found at end of page")
        else:
            checks_passed.append("[C] Placeholder org chart image found")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: Team Directory Analytics
# =============================================================================
def _validate_team_directory_analytics(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Team Directory Analytics page as child of Team Directory with block analysis."""
    errors: list[str] = []

    checks_passed = []

    # Find Team Directory page
    try:
        team_directory = _find_page_by_title(final_state_backend, "Team Directory")
        if not team_directory:
            errors.append("[X] Team Directory page not found")
        else:
            checks_passed.append("[C] Team Directory page found")
    
        team_directory_id = team_directory.get("_id")
        checks_passed.append("[C] Team Directory page found")

        # Find Team Directory Analytics as child
        analytics_page = _find_child_by_title_with_id(final_state_backend, team_directory_id, "team directory analytics")

        if not analytics_page:
            errors.append("[X] Team Directory Analytics not found as child of Team Directory")
        else:
            checks_passed.append("[C] Team Directory Analytics created as child page")

        page_id = analytics_page.get("_id")
        page_blocks = _get_blocks_for_page(final_state_backend, page_id)
        sorted_blocks = sorted(page_blocks, key=lambda b: b.get("order", 0))

        # Check 1: Main heading
        main_heading_found = False
        for block in sorted_blocks:
            if block.get("type") in ["heading1", "heading_1"]:
                content = block.get("content", "")
                if "team directory analytics" in content.lower() and "👥" in content:
                    main_heading_found = True
                    break

        if not main_heading_found:
            errors.append("[X] heading_1 '👥 Team Directory Analytics' not found")
        else:
            checks_passed.append("[C] Main heading found")

        # Check 2: Content Analysis heading
        content_analysis_found = False
        for block in sorted_blocks:
            if block.get("type") in ["heading2", "heading_2"]:
                content = block.get("content", "")
                if "content analysis" in content.lower() and "📊" in content:
                    content_analysis_found = True
                    break

        if not content_analysis_found:
            errors.append("[X] heading_2 '📊 Content Analysis' not found")
        else:
            checks_passed.append("[C] Content Analysis heading found")

        # Check 3: Paragraph with total block count
        total_blocks_found = False
        for block in sorted_blocks:
            if block.get("type") in ["paragraph", "text"]:
                content = block.get("content", "").lower()
                if "total content blocks" in content:
                    total_blocks_found = True
                    break

        if not total_blocks_found:
            errors.append("[X] Paragraph with 'Total content blocks' not found")
        else:
            checks_passed.append("[C] Total blocks paragraph found")

        # Check 4: Block Type Distribution heading
        distribution_found = False
        for block in sorted_blocks:
            if block.get("type") in ["heading3", "heading_3"]:
                content = block.get("content", "")
                if "block type distribution" in content.lower() and "📈" in content:
                    distribution_found = True
                    break

        if not distribution_found:
            errors.append("[X] heading_3 '📈 Block Type Distribution' not found")
        else:
            checks_passed.append("[C] Block Type Distribution heading found")

        # Check 5: Numbered list with block types
        numbered_items = [b for b in sorted_blocks if b.get("type") in ["numberedList", "numbered_list", "numbered_list_item", "numbered"]]
        if len(numbered_items) < 1:
            errors.append("[X] Numbered list with block type counts not found")
        else:
            checks_passed.append("[C] Numbered list with block type counts found")
    
        # Check for block type format
        has_block_count = False
        for item in numbered_items:
            content = item.get("content", "").lower()
            if "blocks" in content:
                has_block_count = True
                break
    
        if not has_block_count:
            errors.append("[X] Numbered list items should contain block counts")
        else:
            checks_passed.append("[C] Block type distribution list found")

        # Check 6: Recent Updates heading
        recent_updates_found = False
        for block in sorted_blocks:
            if block.get("type") in ["heading2", "heading_2"]:
                content = block.get("content", "")
                if "recent updates" in content.lower() and "🔄" in content:
                    recent_updates_found = True
                    break

        if not recent_updates_found:
            errors.append("[X] heading_2 '🔄 Recent Updates' not found")
        else:
            checks_passed.append("[C] Recent Updates heading found")

        # Check 7: Yellow callout with date
        yellow_callout_found = False
        for block in sorted_blocks:
            if block.get("type") == "callout":
                properties = block.get("properties", {})
                bg_color = properties.get("backgroundColor", block.get("backgroundColor", ""))
                icon = properties.get("icon", block.get("icon", ""))
                content = block.get("content", "").lower()
            
                if "yellow" in bg_color.lower() and "📅" in icon and "last analyzed" in content:
                    yellow_callout_found = True
                    break

        if not yellow_callout_found:
            errors.append("[X] Yellow callout with '📅' icon and 'Last analyzed' date not found")
        else:
            checks_passed.append("[C] Yellow callout with date found")

        # Check 8: Divider
        divider_found = any(b.get("type") == "divider" for b in sorted_blocks)
        if not divider_found:
            errors.append("[X] Divider not found")
        else:
            checks_passed.append("[C] Divider found")

        # Check 9: Quote block
        quote_found = False
        for block in sorted_blocks:
            if block.get("type") == "quote":
                content = block.get("content", "").lower()
                if "data-driven" in content or "team collaboration" in content:
                    quote_found = True
                    break

        if not quote_found:
            errors.append("[X] Quote block about data-driven insights not found")
        else:
            checks_passed.append("[C] Quote block found")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: Weekly Standup Callout Insert
# =============================================================================
def _validate_weekly_standup_callout_insert(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Weekly Standup Template has callout inserted at precise location with divider and todo."""
    errors: list[str] = []

    checks_passed = []

    # Find Weekly Standup Template page
    try:
        standup_page = _find_page_by_title(final_state_backend, "Weekly Standup Template")
        if not standup_page:
            errors.append("[X] Weekly Standup Template page not found")
        else:
            checks_passed.append("[C] Weekly Standup Template page found")

        page_id = standup_page.get("_id")
        page_blocks = _get_blocks_for_page(final_state_backend, page_id)
        sorted_blocks = sorted(page_blocks, key=lambda b: b.get("order", 0))
        checks_passed.append("[C] Weekly Standup Template page found")

        # Find key positions
        plan_heading_idx = None
        blockers_heading_idx = None
        api_doc_todo_idx = None
    
        for i, block in enumerate(sorted_blocks):
            block_type = block.get("type", "")
            content = block.get("content", "").lower()
        
            if block_type in ["heading2", "heading_2"]:
                if "what i plan to do" in content or "plan to do next week" in content:
                    plan_heading_idx = i
                elif "blockers" in content:
                    blockers_heading_idx = i
            elif block_type in ["todo", "to_do", "checkbox"]:
                if "documentation for new api" in content or "write documentation" in content:
                    api_doc_todo_idx = i

        # Check 1: Blue callout with style guide text
        blue_callout_found = False
        callout_idx = None
    
        for i, block in enumerate(sorted_blocks):
            if block.get("type") == "callout":
                properties = block.get("properties", {})
                bg_color = properties.get("backgroundColor", block.get("backgroundColor", ""))
                icon = properties.get("icon", block.get("icon", ""))
                content = block.get("content", "")
            
                if "blue" in bg_color.lower() and "📌" in icon:
                    if "style guide" in content.lower() or "documentation must follow" in content.lower():
                        blue_callout_found = True
                        callout_idx = i
                        break

        if not blue_callout_found:
            errors.append("[X] Blue callout with '📌' icon and style guide text not found")
        else:
            checks_passed.append("[C] Blue callout with style guide reminder found")

        # Check 2: Verify callout is after api doc todo and before blockers
        if api_doc_todo_idx is not None and callout_idx is not None and blockers_heading_idx is not None:
            if not (api_doc_todo_idx < callout_idx < blockers_heading_idx):
                errors.append(f"[X] Callout not in correct position (should be after api doc todo, before blockers)")
            else:
                checks_passed.append("[C] Callout positioned correctly")

        # Check 3: Divider after callout
        divider_found = False
        divider_idx = None
        for i, block in enumerate(sorted_blocks):
            if block.get("type") == "divider":
                if callout_idx is not None and i > callout_idx:
                    divider_found = True
                    divider_idx = i
                    break

        if not divider_found:
            errors.append("[X] Divider not found after callout")
        else:
            checks_passed.append("[C] Divider found after callout")

        # Check 4: New todo about API documentation with authentication examples
        new_todo_found = False
        for i, block in enumerate(sorted_blocks):
            if block.get("type") in ["todo", "to_do", "checkbox"]:
                content = block.get("content", "")
                properties = block.get("properties", {})
                is_unchecked = not properties.get("checked", False)
            
                if "api documentation" in content.lower() and "authentication" in content.lower() and "📝" in content:
                    if is_unchecked:
                        # Verify it's after divider
                        if divider_idx is not None and i > divider_idx:
                            new_todo_found = True
                            break

        if not new_todo_found:
            errors.append("[X] New unchecked todo '📝 Update API documentation with authentication examples' not found after divider")
        else:
            checks_passed.append("[C] New API documentation todo found")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: Bug Tracker Status Reorganization
# =============================================================================
def _validate_bug_tracker_status_reorganization(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Bug Tracker reorganized by status with Fixed, Open Critical, and Open Non-Critical sections."""
    errors: list[str] = []

    checks_passed = []

    # Find Bug Tracker page
    try:
        bug_tracker = _find_page_by_title(final_state_backend, "Bug Tracker")
        if not bug_tracker:
            errors.append("[X] Bug Tracker page not found")
        else:
            checks_passed.append("[C] Bug Tracker page found")

        page_id = bug_tracker.get("_id")
        page_blocks = _get_blocks_for_page(final_state_backend, page_id)
        sorted_blocks = sorted(page_blocks, key=lambda b: b.get("order", 0))
        checks_passed.append("[C] Bug Tracker page found")

        # Check for old priority headings (should be removed)
        old_headings_found = []
        for block in sorted_blocks:
            if block.get("type") in ["heading2", "heading_2"]:
                content = block.get("content", "").lower()
                if "critical bugs" in content and "open" not in content:
                    old_headings_found.append("Critical Bugs")
                elif "medium priority" in content:
                    old_headings_found.append("Medium Priority")
                elif "low priority" in content:
                    old_headings_found.append("Low Priority")

        if old_headings_found:
            errors.append(f"[X] Old priority headings should be removed: {', '.join(old_headings_found)}")
        else:
            checks_passed.append("[C] Old priority headings removed")

        # Check for new status-based headings in correct order
        fixed_idx = None
        open_critical_idx = None
        open_noncritical_idx = None
    
        for i, block in enumerate(sorted_blocks):
            if block.get("type") in ["heading2", "heading_2"]:
                content = block.get("content", "")
                content_lower = content.lower()
                if "fixed bugs" in content_lower and "✅" in content:
                    fixed_idx = i
                elif "open critical" in content_lower and "🔴" in content:
                    open_critical_idx = i
                elif "open non-critical" in content_lower and "🟡" in content:
                    open_noncritical_idx = i

        if fixed_idx is None:
            errors.append("[X] heading_2 '✅ Fixed Bugs' not found")
        else:
            checks_passed.append("[C] heading_2 '✅ Fixed Bugs' found")
        if open_critical_idx is None:
            errors.append("[X] heading_2 '🔴 Open Critical Bugs' not found")
        else:
            checks_passed.append("[C] heading_2 '🔴 Open Critical Bugs' found")
        if open_noncritical_idx is None:
            errors.append("[X] heading_2 '🟡 Open Non-Critical Bugs' not found")
        else:
            checks_passed.append("[C] heading_2 '🟡 Open Non-Critical Bugs' found")
    
        # Verify order: Fixed < Open Critical < Open Non-Critical
        if not (fixed_idx < open_critical_idx < open_noncritical_idx):
            errors.append("[X] Section headings not in correct order (Fixed, Open Critical, Open Non-Critical)")
        else:
            checks_passed.append("[C] All three status-based headings found in correct order")

        # Count todos in each section and verify callouts
        sections = [
            ("fixed", fixed_idx, open_critical_idx),
            ("open_critical", open_critical_idx, open_noncritical_idx),
            ("open_noncritical", open_noncritical_idx, len(sorted_blocks))
        ]
    
        callouts_found = 0
        for section_name, start_idx, end_idx in sections:
            # Find callout in section
            for i in range(start_idx + 1, min(start_idx + 5, end_idx)):
                block = sorted_blocks[i]
                if block.get("type") == "callout":
                    properties = block.get("properties", {})
                    bg_color = properties.get("backgroundColor", block.get("backgroundColor", ""))
                    content = block.get("content", "").lower()
                
                    if "gray" in bg_color.lower() and "count:" in content and "bugs" in content:
                        callouts_found += 1
                        break

        if callouts_found < 3:
            errors.append(f"[X] Expected 3 gray callouts with bug counts, found {callouts_found}")
        else:
            checks_passed.append("[C] All three sections have gray callouts with bug counts")

        # Verify todos are in correct sections
        checked_in_fixed = 0
        unchecked_in_fixed = 0
    
        for i in range(fixed_idx + 1, open_critical_idx):
            block = sorted_blocks[i]
            if block.get("type") in ["todo", "to_do", "checkbox"]:
                is_checked = block.get("properties", {}).get("checked", False)
                if is_checked:
                    checked_in_fixed += 1
                else:
                    unchecked_in_fixed += 1

        if unchecked_in_fixed > 0:
            errors.append(f"[X] Fixed Bugs section should only contain checked todos, found {unchecked_in_fixed} unchecked")
        else:
            checks_passed.append("[C] Fixed Bugs section contains only checked todos")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: Documentation Index
# =============================================================================
def _validate_documentation_index(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Documentation Index page as sibling to Architecture with tree and statistics."""
    errors: list[str] = []

    checks_passed = []

    # Find Project Documentation page
    try:
        project_docs = _find_page_by_title(final_state_backend, "Project Documentation")
        if not project_docs:
            errors.append("[X] Project Documentation page not found")
        else:
            checks_passed.append("[C] Project Documentation page found")
    
        project_docs_id = project_docs.get("_id")
        checks_passed.append("[C] Project Documentation page found")

        # Find Documentation Index as child of Project Documentation (sibling to Architecture)
        doc_index = _find_child_by_title_with_id(final_state_backend, project_docs_id, "documentation index")

        if not doc_index:
            errors.append("[X] Documentation Index not found as child of Project Documentation")
        else:
            checks_passed.append("[C] Documentation Index created as sibling to Architecture")

        page_id = doc_index.get("_id")
        page_blocks = _get_blocks_for_page(final_state_backend, page_id)
        sorted_blocks = sorted(page_blocks, key=lambda b: b.get("order", 0))

        # Check 1: Main heading
        main_heading_found = False
        for block in sorted_blocks:
            if block.get("type") in ["heading1", "heading_1"]:
                content = block.get("content", "")
                if "documentation index" in content.lower() and "📚" in content:
                    main_heading_found = True
                    break

        if not main_heading_found:
            errors.append("[X] heading_1 '📚 Documentation Index' not found")
        else:
            checks_passed.append("[C] Main heading found")

        # Check 2: Documentation Tree heading
        tree_found = False
        for block in sorted_blocks:
            if block.get("type") in ["heading2", "heading_2"]:
                content = block.get("content", "")
                if "documentation tree" in content.lower() and "🗂️" in content:
                    tree_found = True
                    break

        if not tree_found:
            errors.append("[X] heading_2 '🗂️ Documentation Tree' not found")
        else:
            checks_passed.append("[C] Documentation Tree heading found")

        # Check 3: Bulleted list items for hierarchy
        bullet_items = [b for b in sorted_blocks if b.get("type") in ["bulletedList", "bulleted_list", "bulleted_list_item"]]
    
        # Check for block count format in bullets
        has_block_counts = False
        for item in bullet_items:
            content = item.get("content", "").lower()
            if "blocks" in content:
                has_block_counts = True
                break
    
        if not has_block_counts:
            errors.append("[X] Bulleted list items should contain block counts")
        else:
            checks_passed.append("[C] Documentation tree with block counts found")

        # Check 4: Statistics heading
        stats_found = False
        for block in sorted_blocks:
            if block.get("type") in ["heading2", "heading_2"]:
                content = block.get("content", "")
                if "statistics" in content.lower() and "📊" in content:
                    stats_found = True
                    break

        if not stats_found:
            errors.append("[X] heading_2 '📊 Statistics' not found")
        else:
            checks_passed.append("[C] Statistics heading found")

        # Check 5: Statistics paragraphs
        stats_keywords = ["total documentation pages", "total content blocks", "deepest nesting"]
        stats_found_count = 0
        for block in sorted_blocks:
            if block.get("type") in ["paragraph", "text"]:
                content = block.get("content", "").lower()
                for keyword in stats_keywords:
                    if keyword in content:
                        stats_found_count += 1
                        break

        if stats_found_count < 2:
            errors.append(f"[X] Expected at least 2 statistics paragraphs, found {stats_found_count}")
        else:
            checks_passed.append("[C] Statistics paragraphs found")

        # Check 6: Gray callout with search tip
        search_callout_found = False
        for block in sorted_blocks:
            if block.get("type") == "callout":
                properties = block.get("properties", {})
                bg_color = properties.get("backgroundColor", block.get("backgroundColor", ""))
                icon = properties.get("icon", block.get("icon", ""))
                content = block.get("content", "").lower()
            
                if "gray" in bg_color.lower() and "🔍" in icon:
                    if "cmd" in content or "ctrl" in content or "search" in content:
                        search_callout_found = True
                        break

        if not search_callout_found:
            errors.append("[X] Gray callout with '🔍' icon and search tip not found")
        else:
            checks_passed.append("[C] Search tip callout found")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: Code Review Checklist
# =============================================================================
def _validate_code_review_checklist(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Code Review Checklist section in Code Examples Repository with todos and quote."""
    errors: list[str] = []

    checks_passed = []

    # Find Code Examples Repository page (or similar)
    try:
        code_examples = _find_page_by_title(final_state_backend, "Code Examples")
        if not code_examples:
            code_examples = _find_page_by_title(final_state_backend, "Code Examples Repository")
        if not code_examples:
            errors.append("[X] Code Examples Repository page not found")
        else:
            checks_passed.append("[C] Code Examples Repository page found")

        page_id = code_examples.get("_id")
        page_blocks = _get_blocks_for_page(final_state_backend, page_id)
        sorted_blocks = sorted(page_blocks, key=lambda b: b.get("order", 0))
        checks_passed.append("[C] Code Examples Repository page found")

        # Check 1: Code Review Checklist heading
        checklist_heading_found = False
        checklist_idx = None
        for i, block in enumerate(sorted_blocks):
            if block.get("type") in ["heading2", "heading_2"]:
                content = block.get("content", "")
                if "code review checklist" in content.lower() and "✅" in content:
                    checklist_heading_found = True
                    checklist_idx = i
                    break

        if not checklist_heading_found:
            errors.append("[X] heading_2 '✅ Code Review Checklist' not found")
        else:
            checks_passed.append("[C] Code Review Checklist heading found")

        # Check 2: Green callout with code block count
        green_callout_found = False
        for block in sorted_blocks:
            if block.get("type") == "callout":
                properties = block.get("properties", {})
                bg_color = properties.get("backgroundColor", block.get("backgroundColor", ""))
                icon = properties.get("icon", block.get("icon", ""))
                content = block.get("content", "").lower()
            
                if "green" in bg_color.lower() and "🔍" in icon:
                    if "merging" in content or "code examples" in content or "review" in content:
                        green_callout_found = True
                        break

        if not green_callout_found:
            errors.append("[X] Green callout with '🔍' icon about merging not found")
        else:
            checks_passed.append("[C] Green callout found")

        # Check 3: Six unchecked todos with specific content
        expected_todos = [
            ("📝", "camelcase"),
            ("🔒", "secrets"),
            ("⚡", "performance"),
            ("🧪", "tests"),
            ("📚", "jsdoc"),
            ("🎯", "dry")
        ]
    
        todo_blocks = [b for b in sorted_blocks if b.get("type") in ["todo", "to_do", "checkbox"]]
    
        found_todos = 0
        for emoji, keyword in expected_todos:
            for todo in todo_blocks:
                content = todo.get("content", "")
                content_lower = content.lower()
                properties = todo.get("properties", {})
                is_unchecked = not properties.get("checked", False)
            
                if emoji in content and keyword in content_lower and is_unchecked:
                    found_todos += 1
                    break

        if found_todos < 6:
            errors.append(f"[X] Expected 6 unchecked todos with specific content, found {found_todos}")
        else:
            checks_passed.append("[C] All 6 checklist todos found")

        # Check 4: Divider
        divider_found = False
        for block in sorted_blocks:
            if block.get("type") == "divider":
                if checklist_idx is not None and sorted_blocks.index(block) > checklist_idx:
                    divider_found = True
                    break

        if not divider_found:
            errors.append("[X] Divider not found after checklist")
        else:
            checks_passed.append("[C] Divider found")

        # Check 5: Paragraph with "Last review conducted"
        review_date_found = False
        for block in sorted_blocks:
            if block.get("type") in ["paragraph", "text"]:
                content = block.get("content", "").lower()
                if "last review conducted" in content:
                    review_date_found = True
                    break

        if not review_date_found:
            errors.append("[X] Paragraph with 'Last review conducted' not found")
        else:
            checks_passed.append("[C] Review date paragraph found")

        # Check 6: Martin Fowler quote
        quote_found = False
        for block in sorted_blocks:
            if block.get("type") == "quote":
                content = block.get("content", "").lower()
                if "martin fowler" in content or "fool can write code" in content or "humans can understand" in content:
                    quote_found = True
                    break

        if not quote_found:
            errors.append("[X] Martin Fowler quote not found")
        else:
            checks_passed.append("[C] Martin Fowler quote found")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: Code Examples Python Callout and TypeScript Bookmark
# =============================================================================
def _validate_code_examples_python_callout_typescript_bookmark(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Code Examples with gray callout after Python, bookmark after TypeScript, and language statistics."""
    errors: list[str] = []

    checks_passed = []

    # Find Code Examples Repository page
    try:
        code_examples = _find_page_by_title(final_state_backend, "Code Examples Repository")
        if not code_examples:
            errors.append("[X] Code Examples Repository page not found")
        else:
            checks_passed.append("[C] Code Examples Repository page found")

        page_id = code_examples.get("_id")
        page_blocks = _get_blocks_for_page(final_state_backend, page_id)
        sorted_blocks = sorted(page_blocks, key=lambda b: b.get("order", 0))
        checks_passed.append("[C] Code Examples Repository page found")

        # Check 1: Gray callout with 🔍 icon containing performance text after Python code
        gray_callout_found = False
        python_section_idx = None
    
        # Find Python Examples section
        for i, block in enumerate(sorted_blocks):
            if block.get("type") in ["heading2", "heading_2"]:
                content = block.get("content", "").lower()
                if "python" in content:
                    python_section_idx = i
                    break
    
        if python_section_idx is not None:
            # Look for gray callout after Python section
            for i in range(python_section_idx + 1, min(python_section_idx + 10, len(sorted_blocks))):
                block = sorted_blocks[i]
                if block.get("type") == "callout":
                    properties = block.get("properties", {})
                    bg_color = properties.get("backgroundColor", block.get("backgroundColor", ""))
                    icon = properties.get("icon", block.get("icon", ""))
                    content = block.get("content", "").lower()
                
                    has_gray_bg = "gray" in bg_color.lower() if bg_color else False
                    has_search_icon = "🔍" in icon if icon else False
                    has_performance_text = "performance" in content and "o(2^n)" in content
                
                    if has_gray_bg and has_search_icon and has_performance_text:
                        gray_callout_found = True
                        break

        if not gray_callout_found:
            errors.append("[X] Gray callout with 🔍 icon and performance text not found after Python section")
        else:
            checks_passed.append("[C] Gray callout with performance text found after Python section")

        # Check 2: Bookmark after TypeScript section
        typescript_section_idx = None
        for i, block in enumerate(sorted_blocks):
            if block.get("type") in ["heading2", "heading_2"]:
                content = block.get("content", "").lower()
                if "typescript" in content:
                    typescript_section_idx = i
                    break
    
        bookmark_found = False
        if typescript_section_idx is not None:
            for i in range(typescript_section_idx + 1, min(typescript_section_idx + 10, len(sorted_blocks))):
                block = sorted_blocks[i]
                if block.get("type") == "bookmark":
                    properties = block.get("properties", {})
                    url = properties.get("url", block.get("url", ""))
                    caption = properties.get("caption", block.get("caption", ""))
                
                    if "typescriptlang" in url.lower() and "interface" in caption.lower():
                        bookmark_found = True
                        break

        if not bookmark_found:
            errors.append("[X] Bookmark with TypeScript interface documentation URL not found after TypeScript section")
        else:
            checks_passed.append("[C] TypeScript bookmark found")

        # Check 3: Language Statistics heading_1 at end of page
        stats_heading_found = False
        for block in reversed(sorted_blocks[:]):
            if block.get("type") in ["heading1", "heading_1"]:
                content = block.get("content", "")
                if "📊" in content and "language statistics" in content.lower():
                    stats_heading_found = True
                    break

        if not stats_heading_found:
            errors.append("[X] heading_1 '📊 Language Statistics' not found at end of page")
        else:
            checks_passed.append("[C] Language Statistics heading_1 found")

        # Check 4: Paragraph with language counts
        lang_paragraph_found = False
        for block in sorted_blocks:
            if block.get("type") in ["paragraph", "text"]:
                content = block.get("content", "").lower()
                if "total code examples" in content and "javascript" in content and "python" in content:
                    lang_paragraph_found = True
                    break

        if not lang_paragraph_found:
            errors.append("[X] Paragraph with language counts not found")
        else:
            checks_passed.append("[C] Language count paragraph found")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: Development Team Summary
# =============================================================================
def _validate_development_team_summary(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Development Team Summary page under Project Documentation with hierarchy analysis."""
    errors: list[str] = []

    checks_passed = []

    # Find Project Documentation page
    try:
        project_docs = _find_page_by_title(final_state_backend, "Project Documentation")
        if not project_docs:
            errors.append("[X] Project Documentation page not found")
        else:
            checks_passed.append("[C] Project Documentation page found")
    
        project_docs_id = project_docs.get("_id")
        checks_passed.append("[C] Project Documentation page found")

        # Find Development Team Summary as child
        dev_summary = None
        child_pages = _get_child_pages(final_state_backend, project_docs_id)
        for child in child_pages:
            if "development team summary" in child.get("title", "").lower():
                dev_summary = child
                break
    
        if not dev_summary:
            errors.append("[X] Development Team Summary page not found as child of Project Documentation")
        else:
            checks_passed.append("[C] Development Team Summary page found as child of Project Documentation")
    
        page_id = dev_summary.get("_id")
        page_blocks = _get_blocks_for_page(final_state_backend, page_id)
        sorted_blocks = sorted(page_blocks, key=lambda b: b.get("order", 0))
        checks_passed.append("[C] Development Team Summary page found under Project Documentation")

        # Check 1: heading_1 '📊 Development Team Documentation Overview'
        overview_heading_found = False
        for block in sorted_blocks:
            if block.get("type") in ["heading1", "heading_1"]:
                content = block.get("content", "")
                if "📊" in content and "development team documentation overview" in content.lower():
                    overview_heading_found = True
                    break

        if not overview_heading_found:
            errors.append("[X] heading_1 '📊 Development Team Documentation Overview' not found")
        else:
            checks_passed.append("[C] Overview heading_1 found")

        # Check 2: heading_2 '📈 Page Hierarchy Analysis'
        hierarchy_heading_found = False
        for block in sorted_blocks:
            if block.get("type") in ["heading2", "heading_2"]:
                content = block.get("content", "")
                if "📈" in content and "page hierarchy analysis" in content.lower():
                    hierarchy_heading_found = True
                    break

        if not hierarchy_heading_found:
            errors.append("[X] heading_2 '📈 Page Hierarchy Analysis' not found")
        else:
            checks_passed.append("[C] Page Hierarchy Analysis heading_2 found")

        # Check 3: Paragraph with total documentation pages count
        total_pages_found = False
        for block in sorted_blocks:
            if block.get("type") in ["paragraph", "text"]:
                content = block.get("content", "").lower()
                if "total documentation pages" in content:
                    total_pages_found = True
                    break

        if not total_pages_found:
            errors.append("[X] Paragraph with 'Total documentation pages' not found")
        else:
            checks_passed.append("[C] Total pages paragraph found")

        # Check 4: heading_2 '🏗️ Architecture Section'
        arch_heading_found = False
        for block in sorted_blocks:
            if block.get("type") in ["heading2", "heading_2"]:
                content = block.get("content", "")
                if "🏗️" in content and "architecture section" in content.lower():
                    arch_heading_found = True
                    break

        if not arch_heading_found:
            errors.append("[X] heading_2 '🏗️ Architecture Section' not found")
        else:
            checks_passed.append("[C] Architecture Section heading_2 found")

        # Check 5: heading_2 '✅ Quick Links'
        quick_links_found = False
        for block in sorted_blocks:
            if block.get("type") in ["heading2", "heading_2"]:
                content = block.get("content", "")
                if "✅" in content and "quick links" in content.lower():
                    quick_links_found = True
                    break

        if not quick_links_found:
            errors.append("[X] heading_2 '✅ Quick Links' not found")
        else:
            checks_passed.append("[C] Quick Links heading_2 found")

        # Check 6: Bookmark blocks exist
        bookmark_count = sum(1 for b in sorted_blocks if b.get("type") == "bookmark")
        if bookmark_count < 1:
            errors.append("[X] No bookmark blocks found")
        else:
            checks_passed.append(f"[C] Found {bookmark_count} bookmark blocks")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: Todo Analytics Report
# =============================================================================
def _validate_todo_analytics_report(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Todo Analytics Report page under Meeting Notes with task metrics."""
    errors: list[str] = []

    checks_passed = []

    # Find Meeting Notes page
    try:
        meeting_notes = _find_page_by_title(final_state_backend, "Meeting Notes")
        if not meeting_notes:
            errors.append("[X] Meeting Notes page not found")
        else:
            checks_passed.append("[C] Meeting Notes page found")
    
        meeting_notes_id = meeting_notes.get("_id")
        checks_passed.append("[C] Meeting Notes page found")

        # Find Todo Analytics Report as child
        analytics_page = None
        child_pages = _get_child_pages(final_state_backend, meeting_notes_id)
        for child in child_pages:
            title = child.get("title", "").lower()
            if "todo analytics" in title or "📊 todo analytics" in title:
                analytics_page = child
                break
    
        if not analytics_page:
            errors.append("[X] Todo Analytics Report page not found as child of Meeting Notes")
        else:
            checks_passed.append("[C] Todo Analytics Report page found as child of Meeting Notes")
    
        page_id = analytics_page.get("_id")
        page_blocks = _get_blocks_for_page(final_state_backend, page_id)
        sorted_blocks = sorted(page_blocks, key=lambda b: b.get("order", 0))
        checks_passed.append("[C] Todo Analytics Report page found under Meeting Notes")

        # Check 1: heading_1 '📊 Meeting Tasks Analytics'
        analytics_heading_found = False
        for block in sorted_blocks:
            if block.get("type") in ["heading1", "heading_1"]:
                content = block.get("content", "")
                if "📊" in content and "meeting tasks analytics" in content.lower():
                    analytics_heading_found = True
                    break

        if not analytics_heading_found:
            errors.append("[X] heading_1 '📊 Meeting Tasks Analytics' not found")
        else:
            checks_passed.append("[C] Meeting Tasks Analytics heading_1 found")

        # Check 2: heading_2 '🎯 Executive Summary'
        summary_heading_found = False
        for block in sorted_blocks:
            if block.get("type") in ["heading2", "heading_2"]:
                content = block.get("content", "")
                if "🎯" in content and "executive summary" in content.lower():
                    summary_heading_found = True
                    break

        if not summary_heading_found:
            errors.append("[X] heading_2 '🎯 Executive Summary' not found")
        else:
            checks_passed.append("[C] Executive Summary heading_2 found")

        # Check 3: Blue callout with 📈 icon and date
        blue_callout_found = False
        for block in sorted_blocks:
            if block.get("type") == "callout":
                properties = block.get("properties", {})
                bg_color = properties.get("backgroundColor", block.get("backgroundColor", ""))
                icon = properties.get("icon", block.get("icon", ""))
                content = block.get("content", "").lower()
            
                has_blue_bg = "blue" in bg_color.lower() if bg_color else False
                has_chart_icon = "📈" in icon if icon else False
                has_date_text = "report generated" in content
            
                if has_blue_bg and has_chart_icon and has_date_text:
                    blue_callout_found = True
                    break

        if not blue_callout_found:
            errors.append("[X] Blue callout with 📈 icon and 'Report generated on' text not found")
        else:
            checks_passed.append("[C] Blue callout with date found")

        # Check 4: heading_3 blocks with '📅' for each meeting
        meeting_heading_count = 0
        for block in sorted_blocks:
            if block.get("type") in ["heading3", "heading_3"]:
                content = block.get("content", "")
                if "📅" in content:
                    meeting_heading_count += 1

        if meeting_heading_count < 1:
            errors.append("[X] No heading_3 with '📅' prefix for meeting pages found")
        else:
            checks_passed.append(f"[C] Found {meeting_heading_count} meeting page headings")

        # Check 5: heading_2 '📋 Consolidated Metrics'
        metrics_heading_found = False
        for block in sorted_blocks:
            if block.get("type") in ["heading2", "heading_2"]:
                content = block.get("content", "")
                if "📋" in content and "consolidated metrics" in content.lower():
                    metrics_heading_found = True
                    break

        if not metrics_heading_found:
            errors.append("[X] heading_2 '📋 Consolidated Metrics' not found")
        else:
            checks_passed.append("[C] Consolidated Metrics heading_2 found")

        # Check 6: Paragraph with total tasks
        total_tasks_found = False
        for block in sorted_blocks:
            if block.get("type") in ["paragraph", "text"]:
                content = block.get("content", "").lower()
                if "total tasks" in content:
                    total_tasks_found = True
                    break

        if not total_tasks_found:
            errors.append("[X] Paragraph with 'Total tasks' not found")
        else:
            checks_passed.append("[C] Total tasks paragraph found")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: Project Roadmap Strategic Priorities
# =============================================================================
def _validate_project_roadmap_strategic_priorities(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Project Roadmap with enhanced strategic priorities and cross-references."""
    errors: list[str] = []

    checks_passed = []

    # Find Project Roadmap page
    try:
        roadmap = _find_page_by_title(final_state_backend, "Project Roadmap")
        if not roadmap:
            errors.append("[X] Project Roadmap page not found")
        else:
            checks_passed.append("[C] Project Roadmap page found")

        page_id = roadmap.get("_id")
        page_blocks = _get_blocks_for_page(final_state_backend, page_id)
        sorted_blocks = sorted(page_blocks, key=lambda b: b.get("order", 0))
        checks_passed.append("[C] Project Roadmap page found")

        # Check 1: Find nested status lines with arrow format
        status_lines_found = 0
        for block in sorted_blocks:
            if block.get("type") in ["bulletedList", "bulleted_list", "bulleted_list_item", "bulleted", "paragraph", "text"]:
                content = block.get("content", "")
                if "→" in content and "status:" in content.lower() and "owner:" in content.lower():
                    status_lines_found += 1

        if status_lines_found < 3:
            errors.append(f"[X] Expected 3 nested status lines with '→ Status: | Owner: | Due:' format, found {status_lines_found}")
        else:
            checks_passed.append(f"[C] Found {status_lines_found} nested status lines")

        # Check 2: Yellow callout with 📊 icon and progress calculation
        yellow_callout_found = False
        for block in sorted_blocks:
            if block.get("type") == "callout":
                properties = block.get("properties", {})
                bg_color = properties.get("backgroundColor", block.get("backgroundColor", ""))
                icon = properties.get("icon", block.get("icon", ""))
                content = block.get("content", "").lower()
            
                has_yellow_bg = "yellow" in bg_color.lower() if bg_color else False
                has_chart_icon = "📊" in icon if icon else False
                has_progress = "progress" in content and ("1 of 3" in content or "33" in content)
            
                if has_yellow_bg and has_chart_icon and has_progress:
                    yellow_callout_found = True
                    break

        if not yellow_callout_found:
            errors.append("[X] Yellow callout with 📊 icon and progress calculation not found")
        else:
            checks_passed.append("[C] Yellow callout with progress found")

        # Check 3: heading_3 '🔗 Related Documents'
        related_docs_found = False
        for block in sorted_blocks:
            if block.get("type") in ["heading3", "heading_3"]:
                content = block.get("content", "")
                if "🔗" in content and "related documents" in content.lower():
                    related_docs_found = True
                    break

        if not related_docs_found:
            errors.append("[X] heading_3 '🔗 Related Documents' not found")
        else:
            checks_passed.append("[C] Related Documents heading_3 found")

        # Check 4: Bookmark with Q1 Sprint Planning
        bookmark_found = False
        for block in sorted_blocks:
            if block.get("type") == "bookmark":
                properties = block.get("properties", {})
                url = properties.get("url", block.get("url", ""))
                content = block.get("content", "").lower()
                caption = properties.get("caption", "").lower()
            
                if "q1" in (content + caption + url).lower():
                    bookmark_found = True
                    break

        if not bookmark_found:
            errors.append("[X] Bookmark with Q1 Sprint Planning not found")
        else:
            checks_passed.append("[C] Q1 Sprint Planning bookmark found")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: Q1 Goals Progress Analysis
# =============================================================================
def _validate_q1_goals_progress_analysis(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Q1 Goals page with progress analysis section and status indicators."""
    errors: list[str] = []

    checks_passed = []

    # Find Project Roadmap page first
    try:
        roadmap = _find_page_by_title(final_state_backend, "Project Roadmap")
        if not roadmap:
            errors.append("[X] Project Roadmap page not found")
        else:
            checks_passed.append("[C] Project Roadmap page found")
    
        roadmap_id = roadmap.get("_id")
    
        # Find Q1 Goals as child
        q1_goals = None
        child_pages = _get_child_pages(final_state_backend, roadmap_id)
        for child in child_pages:
            if "q1 goals" in child.get("title", "").lower():
                q1_goals = child
                break
    
        if not q1_goals:
            # Try finding it directly
            q1_goals = _find_page_by_title(final_state_backend, "Q1 Goals")
    
        if not q1_goals:
            errors.append("[X] Q1 Goals page not found")
        else:
            checks_passed.append("[C] Q1 Goals page found")

        page_id = q1_goals.get("_id")
        page_blocks = _get_blocks_for_page(final_state_backend, page_id)
        sorted_blocks = sorted(page_blocks, key=lambda b: b.get("order", 0))
        checks_passed.append("[C] Q1 Goals page found")

        # Check 1: heading_2 '📊 Progress Analysis'
        progress_heading_found = False
        progress_heading_idx = None
        for i, block in enumerate(sorted_blocks):
            if block.get("type") in ["heading2", "heading_2"]:
                content = block.get("content", "")
                if "📊" in content and "progress analysis" in content.lower():
                    progress_heading_found = True
                    progress_heading_idx = i
                    break

        if not progress_heading_found:
            errors.append("[X] heading_2 '📊 Progress Analysis' not found")
        else:
            checks_passed.append("[C] Progress Analysis heading_2 found")

        # Check 2: Blue callout with 📈 icon and percentage
        blue_callout_found = False
        for block in sorted_blocks:
            if block.get("type") == "callout":
                properties = block.get("properties", {})
                bg_color = properties.get("backgroundColor", block.get("backgroundColor", ""))
                icon = properties.get("icon", block.get("icon", ""))
                content = block.get("content", "").lower()
            
                has_blue_bg = "blue" in bg_color.lower() if bg_color else False
                has_chart_icon = "📈" in icon if icon else False
                has_progress = "q1 progress" in content and "%" in content
            
                if has_blue_bg and has_chart_icon and has_progress:
                    blue_callout_found = True
                    break

        if not blue_callout_found:
            errors.append("[X] Blue callout with 📈 icon and Q1 Progress percentage not found")
        else:
            checks_passed.append("[C] Blue callout with progress percentage found")

        # Check 3: Bold status note for unchecked todos
        status_note_found = False
        for block in sorted_blocks:
            if block.get("type") in ["paragraph", "text"]:
                content = block.get("content", "").lower()
                properties = block.get("properties", {})
                is_bold = properties.get("bold", False)
            
                if "behind schedule" in content or "immediate attention" in content:
                    status_note_found = True
                    break

        if not status_note_found:
            errors.append("[X] Bold status note 'Behind schedule - requires immediate attention' not found")
        else:
            checks_passed.append("[C] Status note for unchecked todo found")

        # Check 4: Timestamp paragraph at end
        timestamp_found = False
        for block in reversed(sorted_blocks):
            if block.get("type") in ["paragraph", "text"]:
                content = block.get("content", "").lower()
                if "analysis generated" in content:
                    timestamp_found = True
                    break

        if not timestamp_found:
            errors.append("[X] Timestamp paragraph 'Analysis generated on:' not found at end")
        else:
            checks_passed.append("[C] Timestamp paragraph found at end")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: PRD Overview Quote and Todos
# =============================================================================
def _validate_prd_overview_quote_todos(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate PRD with Alan Kay quote, review todos under Part headings, and structure callout."""
    errors: list[str] = []

    checks_passed = []

    # Find PRD page
    try:
        prd = _find_page_by_title(final_state_backend, "Comprehensive Product Requirements Document")
        if not prd:
            prd = _find_page_by_title(final_state_backend, "Product Requirements Document")
        if not prd:
            errors.append("[X] Product Requirements Document page not found")
        else:
            checks_passed.append("[C] Product Requirements Document page found")

        page_id = prd.get("_id")
        page_blocks = _get_blocks_for_page(final_state_backend, page_id)
        sorted_blocks = sorted(page_blocks, key=lambda b: b.get("order", 0))
        checks_passed.append("[C] Product Requirements Document page found")

        # Check 1: Quote block with Alan Kay quote
        alan_kay_quote_found = False
        for block in sorted_blocks:
            if block.get("type") == "quote":
                content = block.get("content", "").lower()
                if "alan kay" in content or ("predict the future" in content and "invent it" in content):
                    alan_kay_quote_found = True
                    break

        if not alan_kay_quote_found:
            errors.append("[X] Quote block with Alan Kay quote not found")
        else:
            checks_passed.append("[C] Alan Kay quote found")

        # Check 2: Todo blocks under heading_3 blocks containing 'Part'
        part_headings = []
        for i, block in enumerate(sorted_blocks):
            if block.get("type") in ["heading3", "heading_3"]:
                content = block.get("content", "")
                if "part" in content.lower():
                    part_headings.append(i)

        if len(part_headings) < 1:
            errors.append("[X] No heading_3 blocks containing 'Part' found")
        else:
            checks_passed.append("[C] heading_3 blocks containing 'Part' found")
    
        # Check for todo blocks after Part headings
        todos_found = 0
        for part_idx in part_headings:
            # Look for todo within 3 blocks after the Part heading
            for i in range(part_idx + 1, min(part_idx + 4, len(sorted_blocks))):
                block = sorted_blocks[i]
                if block.get("type") in ["heading3", "heading_3", "heading2", "heading_2"]:
                    break
                if block.get("type") in ["todo", "to_do", "checkbox"]:
                    content = block.get("content", "").lower()
                    if "review" in content or "validate" in content or "stakeholder" in content:
                        todos_found += 1
                        break

        if todos_found < len(part_headings):
            errors.append(f"[X] Expected todo blocks under each Part heading ({len(part_headings)}), found {todos_found}")
        else:
            checks_passed.append(f"[C] Todo blocks found under {todos_found} Part headings")

        # Check 3: Gray callout with document structure counts at end
        structure_callout_found = False
        for block in reversed(sorted_blocks):
            if block.get("type") == "callout":
                properties = block.get("properties", {})
                bg_color = properties.get("backgroundColor", block.get("backgroundColor", ""))
                content = block.get("content", "").lower()
            
                has_gray_bg = "gray" in bg_color.lower() if bg_color else False
                has_structure = "document structure" in content and "section" in content
            
                if has_gray_bg and has_structure:
                    structure_callout_found = True
                    break

        if not structure_callout_found:
            errors.append("[X] Gray callout with document structure counts not found at end")
        else:
            checks_passed.append("[C] Document structure callout found")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: Onboarding Guide Quote and Checklist
# =============================================================================
def _validate_onboarding_guide_quote_checklist(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Onboarding Guide with quote after First Week Goals and checklist summary."""
    errors: list[str] = []

    checks_passed = []

    # Find Onboarding Guide page
    try:
        onboarding = _find_page_by_title(final_state_backend, "Onboarding Guide")
        if not onboarding:
            errors.append("[X] Onboarding Guide page not found")
        else:
            checks_passed.append("[C] Onboarding Guide page found")

        page_id = onboarding.get("_id")
        page_blocks = _get_blocks_for_page(final_state_backend, page_id)
        sorted_blocks = sorted(page_blocks, key=lambda b: b.get("order", 0))
        checks_passed.append("[C] Onboarding Guide page found")

        # Find First Week Goals heading
        first_week_idx = None
        for i, block in enumerate(sorted_blocks):
            if block.get("type") in ["heading2", "heading_2"]:
                content = block.get("content", "").lower()
                if "first week goals" in content:
                    first_week_idx = i
                    break

        if first_week_idx is None:
            errors.append("[X] First Week Goals heading not found")
        else:
            checks_passed.append("[C] First Week Goals heading found")

        # Check 1: Quote block after First Week Goals heading
        quote_found = False
        quote_correct_position = False
        for i in range(first_week_idx + 1, min(first_week_idx + 5, len(sorted_blocks))):
            block = sorted_blocks[i]
            if block.get("type") == "quote":
                content = block.get("content", "").lower()
                if "success" in content and "first week" in content and "foundation" in content:
                    quote_found = True
                    # Check it's before numbered list items
                    for j in range(first_week_idx + 1, i):
                        if sorted_blocks[j].get("type") in ["numberedList", "numbered_list", "numbered_list_item"]:
                            break
                    else:
                        quote_correct_position = True
                    break

        if not quote_found:
            errors.append("[X] Quote block with success/foundation text not found after First Week Goals")
        else:
            checks_passed.append("[C] Quote block found after First Week Goals heading")

        # Check 2: Divider after last numbered list
        divider_found = False
        for block in sorted_blocks:
            if block.get("type") == "divider":
                divider_found = True
                break

        if not divider_found:
            errors.append("[X] Divider not found")
        else:
            checks_passed.append("[C] Divider found")

        # Check 3: heading_3 '✅ Onboarding Checklist Summary'
        checklist_summary_found = False
        for block in sorted_blocks:
            if block.get("type") in ["heading3", "heading_3"]:
                content = block.get("content", "")
                if "✅" in content and "onboarding checklist summary" in content.lower():
                    checklist_summary_found = True
                    break

        if not checklist_summary_found:
            errors.append("[X] heading_3 '✅ Onboarding Checklist Summary' not found")
        else:
            checks_passed.append("[C] Checklist Summary heading_3 found")

        # Check 4: Paragraph with total onboarding tasks count
        task_count_found = False
        for block in sorted_blocks:
            if block.get("type") in ["paragraph", "text"]:
                content = block.get("content", "").lower()
                if "total onboarding tasks" in content:
                    task_count_found = True
                    break

        if not task_count_found:
            errors.append("[X] Paragraph with 'Total onboarding tasks' not found")
        else:
            checks_passed.append("[C] Task count paragraph found")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: PRD Swap Overview Sections
# =============================================================================
def _validate_prd_swap_overview_sections(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate PRD with swapped Overview section and gray restructure callout at top."""
    errors: list[str] = []

    checks_passed = []

    # Find PRD page
    try:
        prd = _find_page_by_title(final_state_backend, "Product Requirements Document")
        if not prd:
            errors.append("[X] Product Requirements Document page not found")
        else:
            checks_passed.append("[C] Product Requirements Document page found")

        page_id = prd.get("_id")
        page_blocks = _get_blocks_for_page(final_state_backend, page_id)
        sorted_blocks = sorted(page_blocks, key=lambda b: b.get("order", 0))
        checks_passed.append("[C] Product Requirements Document page found")

        # Check 1: Gray callout at the very beginning with 📝 icon
        first_callout_correct = False
        for block in sorted_blocks[:5]:  # Check first few blocks
            if block.get("type") == "callout":
                properties = block.get("properties", {})
                bg_color = properties.get("backgroundColor", block.get("backgroundColor", ""))
                icon = properties.get("icon", block.get("icon", ""))
                content = block.get("content", "").lower()
            
                has_gray_bg = "gray" in bg_color.lower() if bg_color else False
                has_pencil_icon = "📝" in icon if icon else False
                has_restructure_text = "restructured" in content or "readability" in content
            
                if has_gray_bg and has_pencil_icon and has_restructure_text:
                    first_callout_correct = True
                    break

        if not first_callout_correct:
            errors.append("[X] Gray callout with 📝 icon and restructure text not found at beginning")
        else:
            checks_passed.append("[C] Gray restructure callout found at top")

        # Check 2: Verify section swap - find Overview heading position relative to other major sections
        overview_idx = None
        other_section_idx = None
    
        for i, block in enumerate(sorted_blocks):
            if block.get("type") in ["heading2", "heading_2"]:
                content = block.get("content", "").lower()
                if "overview" in content and overview_idx is None:
                    overview_idx = i
                elif overview_idx is not None and other_section_idx is None:
                    # This is the section after Overview
                    other_section_idx = i
                    break

        if overview_idx is None:
            errors.append("[X] Overview section not found")
        else:
            checks_passed.append("[C] Overview section found")
    
        checks_passed.append("[C] Overview section found - swap verification requires manual check")

        # Check 3: All three Overview sub-parts exist
        part_count = 0
        for block in sorted_blocks:
            if block.get("type") in ["heading3", "heading_3"]:
                content = block.get("content", "").lower()
                if "overview - part" in content:
                    part_count += 1

        if part_count < 3:
            errors.append(f"[X] Expected 3 Overview sub-parts, found {part_count}")
        else:
            checks_passed.append(f"[C] Found {part_count} Overview sub-parts")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: Code Examples Repository Statistics
# =============================================================================
def _validate_code_examples_repository_statistics(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Code Examples Repository with statistics section and block counts."""
    errors: list[str] = []

    checks_passed = []

    # Find Code Examples Repository page
    try:
        code_examples = _find_page_by_title(final_state_backend, "Code Examples Repository")
        if not code_examples:
            errors.append("[X] Code Examples Repository page not found")
        else:
            checks_passed.append("[C] Code Examples Repository page found")

        page_id = code_examples.get("_id")
        page_blocks = _get_blocks_for_page(final_state_backend, page_id)
        sorted_blocks = sorted(page_blocks, key=lambda b: b.get("order", 0))
        checks_passed.append("[C] Code Examples Repository page found")

        # Check 1: heading_2 '📊 Repository Statistics'
        stats_heading_found = False
        for block in sorted_blocks:
            if block.get("type") in ["heading2", "heading_2"]:
                content = block.get("content", "")
                if "📊" in content and "repository statistics" in content.lower():
                    stats_heading_found = True
                    break

        if not stats_heading_found:
            errors.append("[X] heading_2 '📊 Repository Statistics' not found")
        else:
            checks_passed.append("[C] Repository Statistics heading_2 found")

        # Check 2: Blue callout with 📈 icon and date
        blue_callout_found = False
        for block in sorted_blocks:
            if block.get("type") == "callout":
                properties = block.get("properties", {})
                bg_color = properties.get("backgroundColor", block.get("backgroundColor", ""))
                icon = properties.get("icon", block.get("icon", ""))
                content = block.get("content", "").lower()
            
                has_blue_bg = "blue" in bg_color.lower() if bg_color else False
                has_chart_icon = "📈" in icon if icon else False
                has_date = "last updated" in content
            
                if has_blue_bg and has_chart_icon and has_date:
                    blue_callout_found = True
                    break

        if not blue_callout_found:
            errors.append("[X] Blue callout with 📈 icon and 'Last updated' text not found")
        else:
            checks_passed.append("[C] Blue callout with date found")

        # Check 3: heading_3 '📋 Content Breakdown'
        breakdown_heading_found = False
        for block in sorted_blocks:
            if block.get("type") in ["heading3", "heading_3"]:
                content = block.get("content", "")
                if "📋" in content and "content breakdown" in content.lower():
                    breakdown_heading_found = True
                    break

        if not breakdown_heading_found:
            errors.append("[X] heading_3 '📋 Content Breakdown' not found")
        else:
            checks_passed.append("[C] Content Breakdown heading_3 found")

        # Check 4: Numbered list with block counts
        numbered_items = [b for b in sorted_blocks if b.get("type") in ["numberedList", "numbered_list", "numbered_list_item", "numbered"]]
    
        # Check that numbered list contains expected metrics
        has_total = False
        has_code_blocks = False
        has_headings = False
    
        for item in numbered_items:
            content = item.get("content", "").lower()
            if "total blocks" in content:
                has_total = True
            if "code blocks" in content:
                has_code_blocks = True
            if "headings" in content:
                has_headings = True

        if not (has_total and has_code_blocks and has_headings):
            errors.append(f"[X] Numbered list missing expected metrics (total: {has_total}, code: {has_code_blocks}, headings: {has_headings})")
        else:
            checks_passed.append("[C] Numbered list with block counts found")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: Bug Tracker Priority Matrix
# =============================================================================
def _validate_bug_tracker_priority_matrix(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Bug Tracker with priority matrix section and resolution rate."""
    errors: list[str] = []

    checks_passed = []

    # Find Bug Tracker page
    try:
        bug_tracker = _find_page_by_title(final_state_backend, "Bug Tracker")
        if not bug_tracker:
            errors.append("[X] Bug Tracker page not found")
        else:
            checks_passed.append("[C] Bug Tracker page found")

        page_id = bug_tracker.get("_id")
        page_blocks = _get_blocks_for_page(final_state_backend, page_id)
        sorted_blocks = sorted(page_blocks, key=lambda b: b.get("order", 0))
        checks_passed.append("[C] Bug Tracker page found")

        # Check 1: heading_2 '🎯 Bug Priority Matrix' near top
        matrix_heading_found = False
        matrix_heading_idx = None
        for i, block in enumerate(sorted_blocks):
            if block.get("type") in ["heading2", "heading_2"]:
                content = block.get("content", "")
                if "🎯" in content and "bug priority matrix" in content.lower():
                    matrix_heading_found = True
                    matrix_heading_idx = i
                    break

        if not matrix_heading_found:
            errors.append("[X] heading_2 '🎯 Bug Priority Matrix' not found")
        else:
            checks_passed.append("[C] Bug Priority Matrix heading_2 found")

        # Check 2: Red callout with 🚨 icon
        red_callout_found = False
        for block in sorted_blocks:
            if block.get("type") == "callout":
                properties = block.get("properties", {})
                bg_color = properties.get("backgroundColor", block.get("backgroundColor", ""))
                icon = properties.get("icon", block.get("icon", ""))
                content = block.get("content", "").lower()
            
                has_red_bg = "red" in bg_color.lower() if bg_color else False
                has_alert_icon = "🚨" in icon if icon else False
                has_critical_text = "critical" in content and "immediate" in content
            
                if has_red_bg and has_alert_icon and has_critical_text:
                    red_callout_found = True
                    break

        if not red_callout_found:
            errors.append("[X] Red callout with 🚨 icon and critical issues text not found")
        else:
            checks_passed.append("[C] Red callout with critical text found")

        # Check 3: heading_3 'Priority Breakdown:'
        breakdown_heading_found = False
        for block in sorted_blocks:
            if block.get("type") in ["heading3", "heading_3"]:
                content = block.get("content", "").lower()
                if "priority breakdown" in content:
                    breakdown_heading_found = True
                    break

        if not breakdown_heading_found:
            errors.append("[X] heading_3 'Priority Breakdown:' not found")
        else:
            checks_passed.append("[C] Priority Breakdown heading_3 found")

        # Check 4: Bulleted list with priority colors (🔴, 🟡, 🟢)
        priority_items_found = 0
        for block in sorted_blocks:
            if block.get("type") in ["bulletedList", "bulleted_list", "bulleted_list_item", "bulleted"]:
                content = block.get("content", "")
                if "🔴" in content and "critical" in content.lower():
                    priority_items_found += 1
                elif "🟡" in content and "high" in content.lower():
                    priority_items_found += 1
                elif "🟢" in content and "low" in content.lower():
                    priority_items_found += 1

        if priority_items_found < 3:
            errors.append(f"[X] Expected 3 priority items (🔴/🟡/🟢), found {priority_items_found}")
        else:
            checks_passed.append("[C] All priority color items found")

        # Check 5: heading_3 'Resolution Rate'
        resolution_heading_found = False
        for block in sorted_blocks:
            if block.get("type") in ["heading3", "heading_3"]:
                content = block.get("content", "").lower()
                if "resolution rate" in content:
                    resolution_heading_found = True
                    break

        if not resolution_heading_found:
            errors.append("[X] heading_3 'Resolution Rate' not found")
        else:
            checks_passed.append("[C] Resolution Rate heading_3 found")

        # Check 6: Paragraph with resolution percentage
        resolution_paragraph_found = False
        for block in sorted_blocks:
            if block.get("type") in ["paragraph", "text"]:
                content = block.get("content", "").lower()
                if "resolution rate" in content and "%" in content:
                    resolution_paragraph_found = True
                    break

        if not resolution_paragraph_found:
            errors.append("[X] Paragraph with resolution rate percentage not found")
        else:
            checks_passed.append("[C] Resolution rate paragraph found")

        # Check 7: Quote block with focus message
        quote_found = False
        for block in sorted_blocks:
            if block.get("type") == "quote":
                content = block.get("content", "").lower()
                if "focus" in content and "critical" in content:
                    quote_found = True
                    break

        if not quote_found:
            errors.append("[X] Quote block with 'Focus on critical bugs first' not found")
        else:
            checks_passed.append("[C] Focus quote found")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: Project Guidelines Performance Section
# =============================================================================
def _validate_project_guidelines_performance(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Project Guidelines with Performance Guidelines section and colored callouts."""
    errors: list[str] = []

    checks_passed = []

    # Find Project Guidelines page
    try:
        guidelines = _find_page_by_title(final_state_backend, "Project Guidelines & Best Practices")
        if not guidelines:
            guidelines = _find_page_by_title(final_state_backend, "Project Guidelines")
        if not guidelines:
            errors.append("[X] Project Guidelines page not found")
        else:
            checks_passed.append("[C] Project Guidelines page found")

        page_id = guidelines.get("_id")
        page_blocks = _get_blocks_for_page(final_state_backend, page_id)
        sorted_blocks = sorted(page_blocks, key=lambda b: b.get("order", 0))
        checks_passed.append("[C] Project Guidelines page found")

        # Check 1: Divider exists (before Performance Guidelines)
        divider_found = False
        for block in sorted_blocks:
            if block.get("type") == "divider":
                divider_found = True
                break

        if not divider_found:
            errors.append("[X] Divider not found")
        else:
            checks_passed.append("[C] Divider found")

        # Check 2: heading_2 '🎯 Performance Guidelines'
        perf_heading_found = False
        perf_heading_idx = None
        for i, block in enumerate(sorted_blocks):
            if block.get("type") in ["heading2", "heading_2"]:
                content = block.get("content", "")
                if "🎯" in content and "performance guidelines" in content.lower():
                    perf_heading_found = True
                    perf_heading_idx = i
                    break

        if not perf_heading_found:
            errors.append("[X] heading_2 '🎯 Performance Guidelines' not found")
        else:
            checks_passed.append("[C] Performance Guidelines heading_2 found")

        # Check 3: Yellow callout with ⏱️ icon
        yellow_callout_found = False
        for block in sorted_blocks:
            if block.get("type") == "callout":
                properties = block.get("properties", {})
                bg_color = properties.get("backgroundColor", block.get("backgroundColor", ""))
                icon = properties.get("icon", block.get("icon", ""))
                content = block.get("content", "").lower()
            
                has_yellow_bg = "yellow" in bg_color.lower() if bg_color else False
                has_timer_icon = "⏱️" in icon if icon else False
                has_perf_text = "performance" in content and "100ms" in content
            
                if has_yellow_bg and has_timer_icon and has_perf_text:
                    yellow_callout_found = True
                    break

        if not yellow_callout_found:
            errors.append("[X] Yellow callout with ⏱️ icon and performance text not found")
        else:
            checks_passed.append("[C] Yellow performance callout found")

        # Check 4: Blue callout with 📊 icon
        blue_callout_found = False
        for block in sorted_blocks:
            if block.get("type") == "callout":
                properties = block.get("properties", {})
                bg_color = properties.get("backgroundColor", block.get("backgroundColor", ""))
                icon = properties.get("icon", block.get("icon", ""))
                content = block.get("content", "").lower()
            
                has_blue_bg = "blue" in bg_color.lower() if bg_color else False
                has_chart_icon = "📊" in icon if icon else False
                has_monitoring_text = "monitoring" in content
            
                if has_blue_bg and has_chart_icon and has_monitoring_text:
                    blue_callout_found = True
                    break

        if not blue_callout_found:
            errors.append("[X] Blue callout with 📊 icon and monitoring text not found")
        else:
            checks_passed.append("[C] Blue monitoring callout found")

        # Check 5: Green callout with 🚀 icon
        green_callout_found = False
        for block in sorted_blocks:
            if block.get("type") == "callout":
                properties = block.get("properties", {})
                bg_color = properties.get("backgroundColor", block.get("backgroundColor", ""))
                icon = properties.get("icon", block.get("icon", ""))
                content = block.get("content", "").lower()
            
                has_green_bg = "green" in bg_color.lower() if bg_color else False
                has_rocket_icon = "🚀" in icon if icon else False
                has_optimization_text = "optimization" in content
            
                if has_green_bg and has_rocket_icon and has_optimization_text:
                    green_callout_found = True
                    break

        if not green_callout_found:
            errors.append("[X] Green callout with 🚀 icon and optimization text not found")
        else:
            checks_passed.append("[C] Green optimization callout found")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: PRD Technical Specifications
# =============================================================================
def _validate_prd_technical_specifications(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate PRD with Technical Specifications section and swapped Part 2/Part 3 content."""
    errors: list[str] = []

    checks_passed = []

    # Find PRD page
    try:
        prd = _find_page_by_title(final_state_backend, "Comprehensive Product Requirements Document")
        if not prd:
            prd = _find_page_by_title(final_state_backend, "Product Requirements Document")
        if not prd:
            errors.append("[X] Product Requirements Document page not found")
        else:
            checks_passed.append("[C] Product Requirements Document page found")

        page_id = prd.get("_id")
        page_blocks = _get_blocks_for_page(final_state_backend, page_id)
        sorted_blocks = sorted(page_blocks, key=lambda b: b.get("order", 0))
        checks_passed.append("[C] Product Requirements Document page found")

        # Check 1: heading_3 '🔍 Technical Specifications'
        tech_spec_found = False
        tech_spec_idx = None
        for i, block in enumerate(sorted_blocks):
            if block.get("type") in ["heading3", "heading_3"]:
                content = block.get("content", "")
                if "🔍" in content and "technical specifications" in content.lower():
                    tech_spec_found = True
                    tech_spec_idx = i
                    break

        if not tech_spec_found:
            errors.append("[X] heading_3 '🔍 Technical Specifications' not found")
        else:
            checks_passed.append("[C] Technical Specifications heading_3 found")

        # Check 2: Three paragraphs with performance metrics
        metric_count = 0
        expected_metrics = ["page load time", "memory usage", "api response"]
    
        for block in sorted_blocks:
            if block.get("type") in ["paragraph", "text"]:
                content = block.get("content", "").lower()
                for metric in expected_metrics:
                    if metric in content:
                        metric_count += 1
                        break

        if metric_count < 3:
            errors.append(f"[X] Expected 3 performance metric paragraphs, found {metric_count}")
        else:
            checks_passed.append("[C] Performance metric paragraphs found")

        # Check 3: Part headings exist
        part_headings = []
        for i, block in enumerate(sorted_blocks):
            if block.get("type") in ["heading3", "heading_3"]:
                content = block.get("content", "").lower()
                if "overview - part" in content:
                    part_headings.append((i, content))

        if len(part_headings) < 3:
            errors.append(f"[X] Expected 3 Overview Part headings, found {len(part_headings)}")
        else:
            checks_passed.append(f"[C] Found {len(part_headings)} Overview Part headings")

        # Swap verification would require knowing original content
        checks_passed.append("[C] Part sections found - swap verification requires content analysis")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: Sprint Planning Follow-up Schedule
# =============================================================================
def _validate_sprint_planning_followup_schedule(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Sprint Planning with Follow-up Schedule section and todos."""
    errors: list[str] = []

    checks_passed = []

    # Find Sprint Planning page (under Meeting Notes)
    try:
        sprint_planning = _find_page_by_title(final_state_backend, "Sprint Planning - Jan 15")
        if not sprint_planning:
            sprint_planning = _find_page_by_title(final_state_backend, "Sprint Planning")
        if not sprint_planning:
            errors.append("[X] Sprint Planning page not found")
        else:
            checks_passed.append("[C] Sprint Planning page found")

        page_id = sprint_planning.get("_id")
        page_blocks = _get_blocks_for_page(final_state_backend, page_id)
        sorted_blocks = sorted(page_blocks, key=lambda b: b.get("order", 0))
        checks_passed.append("[C] Sprint Planning page found")

        # Check 1: heading_2 '📅 Follow-up Schedule'
        followup_heading_found = False
        followup_heading_idx = None
        for i, block in enumerate(sorted_blocks):
            if block.get("type") in ["heading2", "heading_2"]:
                content = block.get("content", "")
                if "📅" in content and "follow-up schedule" in content.lower():
                    followup_heading_found = True
                    followup_heading_idx = i
                    break

        if not followup_heading_found:
            errors.append("[X] heading_2 '📅 Follow-up Schedule' not found")
        else:
            checks_passed.append("[C] Follow-up Schedule heading_2 found")

        # Check 2: Paragraph with next sprint planning date
        date_paragraph_found = False
        for block in sorted_blocks:
            if block.get("type") in ["paragraph", "text"]:
                content = block.get("content", "").lower()
                if "next sprint planning" in content and "january" in content:
                    date_paragraph_found = True
                    break

        if not date_paragraph_found:
            errors.append("[X] Paragraph with 'Next sprint planning: January 29, 2024' not found")
        else:
            checks_passed.append("[C] Next sprint planning date paragraph found")

        # Check 3: Three unchecked todos with specific texts
        expected_todos = ["send meeting notes", "update sprint velocity", "schedule mid-sprint"]
        todo_count = 0
    
        for block in sorted_blocks:
            if block.get("type") in ["todo", "to_do", "checkbox"]:
                content = block.get("content", "").lower()
                properties = block.get("properties", {})
                is_checked = properties.get("checked", False)
            
                if not is_checked:
                    for expected in expected_todos:
                        if expected in content:
                            todo_count += 1
                            break

        if todo_count < 3:
            errors.append(f"[X] Expected 3 unchecked todos with specific texts, found {todo_count}")
        else:
            checks_passed.append(f"[C] Found {todo_count} required unchecked todos")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: PRD Performance Callout
# =============================================================================
def _validate_prd_performance_callout(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate PRD with purple performance callout, divider, and technical review date."""
    errors: list[str] = []

    checks_passed = []

    # Find PRD page
    try:
        prd = _find_page_by_title(final_state_backend, "Comprehensive Product Requirements Document")
        if not prd:
            prd = _find_page_by_title(final_state_backend, "Product Requirements Document")
        if not prd:
            errors.append("[X] Product Requirements Document page not found")
        else:
            checks_passed.append("[C] Product Requirements Document page found")

        page_id = prd.get("_id")
        page_blocks = _get_blocks_for_page(final_state_backend, page_id)
        sorted_blocks = sorted(page_blocks, key=lambda b: b.get("order", 0))
        checks_passed.append("[C] Product Requirements Document page found")

        # Check 1: Purple callout with ⚡ icon and performance requirement text
        purple_callout_found = False
        for block in sorted_blocks:
            if block.get("type") == "callout":
                properties = block.get("properties", {})
                bg_color = properties.get("backgroundColor", block.get("backgroundColor", ""))
                icon = properties.get("icon", block.get("icon", ""))
                content = block.get("content", "").lower()
            
                has_purple_bg = "purple" in bg_color.lower() if bg_color else False
                has_lightning_icon = "⚡" in icon if icon else False
                has_perf_text = "performance requirement" in content and "500ms" in content
            
                if has_purple_bg and has_lightning_icon and has_perf_text:
                    purple_callout_found = True
                    break

        if not purple_callout_found:
            errors.append("[X] Purple callout with ⚡ icon and 500ms performance requirement not found")
        else:
            checks_passed.append("[C] Purple performance callout found")

        # Check 2: Divider exists after callout
        divider_found = False
        for block in sorted_blocks:
            if block.get("type") == "divider":
                divider_found = True
                break

        if not divider_found:
            errors.append("[X] Divider not found after callout")
        else:
            checks_passed.append("[C] Divider found")

        # Check 3: Italic paragraph with 'Last technical review' at end of Overview section
        review_paragraph_found = False
        for block in sorted_blocks:
            if block.get("type") in ["paragraph", "text"]:
                content = block.get("content", "").lower()
                if "last technical review" in content:
                    review_paragraph_found = True
                    break

        if not review_paragraph_found:
            errors.append("[X] Paragraph with 'Last technical review:' not found")
        else:
            checks_passed.append("[C] Technical review paragraph found")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: Engineering Wiki Swap Sections
# =============================================================================
def _validate_engineering_wiki_swap_sections(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Engineering Wiki with swapped sections, security config, and warning callout."""
    errors: list[str] = []

    checks_passed = []

    # Find Engineering Wiki page
    try:
        wiki = _find_page_by_title(final_state_backend, "Engineering Wiki")
        if not wiki:
            errors.append("[X] Engineering Wiki page not found")
        else:
            checks_passed.append("[C] Engineering Wiki page found")

        page_id = wiki.get("_id")
        page_blocks = _get_blocks_for_page(final_state_backend, page_id)
        sorted_blocks = sorted(page_blocks, key=lambda b: b.get("order", 0))
        checks_passed.append("[C] Engineering Wiki page found")

        # Check for section headings and their positions
        dev_setup_idx = None
        tech_stack_idx = None
    
        for i, block in enumerate(sorted_blocks):
            if block.get("type") in ["heading2", "heading_2"]:
                content = block.get("content", "").lower()
                if "development setup" in content and dev_setup_idx is None:
                    dev_setup_idx = i
                elif "tech stack" in content and tech_stack_idx is None:
                    tech_stack_idx = i

        # Check 1: Verify swap - Development Setup should come before Tech Stack now
        if dev_setup_idx is not None and tech_stack_idx is not None:
            if dev_setup_idx < tech_stack_idx:
                checks_passed.append("[C] Sections swapped: Development Setup now before Tech Stack")
            else:
                errors.append("[X] Sections not swapped: Development Setup should appear before Tech Stack")
        elif dev_setup_idx is None:
            errors.append("[X] Development Setup section not found")
        elif tech_stack_idx is None:
            errors.append("[X] Tech Stack section not found")
        else:
            checks_passed.append("[C] Tech Stack section found")

        # Check 2: heading_3 '🔐 Security Configuration'
        security_heading_found = False
        for block in sorted_blocks:
            if block.get("type") in ["heading3", "heading_3"]:
                content = block.get("content", "")
                if "🔐" in content and "security configuration" in content.lower():
                    security_heading_found = True
                    break

        if not security_heading_found:
            errors.append("[X] heading_3 '🔐 Security Configuration' not found")
        else:
            checks_passed.append("[C] Security Configuration heading_3 found")

        # Check 3: Code block with bash/export statements
        code_block_found = False
        for block in sorted_blocks:
            if block.get("type") == "code":
                content = block.get("content", "").lower()
                properties = block.get("properties", {})
                language = properties.get("language", "").lower()
            
                has_exports = "jwt_secret" in content or "api_rate_limit" in content
            
                if has_exports:
                    code_block_found = True
                    break

        if not code_block_found:
            errors.append("[X] Code block with JWT_SECRET and API_RATE_LIMIT exports not found")
        else:
            checks_passed.append("[C] Security code block found")

        # Check 4: Yellow callout with ⚠️ icon and warning text
        yellow_callout_found = False
        for block in sorted_blocks:
            if block.get("type") == "callout":
                properties = block.get("properties", {})
                bg_color = properties.get("backgroundColor", block.get("backgroundColor", ""))
                icon = properties.get("icon", block.get("icon", ""))
                content = block.get("content", "").lower()
            
                has_yellow_bg = "yellow" in bg_color.lower() if bg_color else False
                has_warning_icon = "⚠️" in icon if icon else False
                has_important_text = "important" in content and "tech stack" in content
            
                if has_yellow_bg and has_warning_icon and has_important_text:
                    yellow_callout_found = True
                    break

        if not yellow_callout_found:
            errors.append("[X] Yellow callout with ⚠️ icon and 'Important: Complete Tech Stack' text not found")
        else:
            checks_passed.append("[C] Yellow warning callout found")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: Sprint Planning Velocity Tracking
# =============================================================================
def _validate_sprint_planning_velocity_tracking(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Sprint Planning with velocity tracking section and story points."""
    errors: list[str] = []

    checks_passed = []

    # Find Sprint Planning page
    try:
        sprint_planning = _find_page_by_title(final_state_backend, "Sprint Planning - Jan 15")
        if not sprint_planning:
            sprint_planning = _find_page_by_title(final_state_backend, "Sprint Planning")
        if not sprint_planning:
            errors.append("[X] Sprint Planning page not found")
        else:
            checks_passed.append("[C] Sprint Planning page found")

        page_id = sprint_planning.get("_id")
        page_blocks = _get_blocks_for_page(final_state_backend, page_id)
        sorted_blocks = sorted(page_blocks, key=lambda b: b.get("order", 0))
        checks_passed.append("[C] Sprint Planning page found")

        # Check 1: heading_2 '📊 Sprint Velocity Tracking'
        velocity_heading_found = False
        for block in sorted_blocks:
            if block.get("type") in ["heading2", "heading_2"]:
                content = block.get("content", "")
                if "📊" in content and "sprint velocity tracking" in content.lower():
                    velocity_heading_found = True
                    break

        if not velocity_heading_found:
            errors.append("[X] heading_2 '📊 Sprint Velocity Tracking' not found")
        else:
            checks_passed.append("[C] Sprint Velocity Tracking heading_2 found")

        # Check 2: Green callout with story points
        green_callout_found = False
        for block in sorted_blocks:
            if block.get("type") == "callout":
                properties = block.get("properties", {})
                bg_color = properties.get("backgroundColor", block.get("backgroundColor", ""))
                content = block.get("content", "").lower()
            
                has_green_bg = "green" in bg_color.lower() if bg_color else False
                has_story_points = "story points" in content and "21" in content
            
                if has_green_bg and has_story_points:
                    green_callout_found = True
                    break

        if not green_callout_found:
            errors.append("[X] Green callout with 'Story Points This Sprint: 21' not found")
        else:
            checks_passed.append("[C] Green callout with story points found")

        # Check 3: Numbered items with point values (8 pts, 5 pts, etc.)
        points_found = 0
        for block in sorted_blocks:
            if block.get("type") in ["numberedList", "numbered_list", "numbered_list_item", "numbered"]:
                content = block.get("content", "")
                if "pts)" in content.lower() or "pts" in content.lower():
                    points_found += 1

        if points_found < 3:
            errors.append(f"[X] Expected 3 numbered items with point values, found {points_found}")
        else:
            checks_passed.append(f"[C] Found {points_found} items with point values")

        # Check 4: heading_2 '🎯 Mid-Sprint Review'
        midsprint_heading_found = False
        for block in sorted_blocks:
            if block.get("type") in ["heading2", "heading_2"]:
                content = block.get("content", "")
                if "🎯" in content and "mid-sprint review" in content.lower():
                    midsprint_heading_found = True
                    break

        if not midsprint_heading_found:
            errors.append("[X] heading_2 '🎯 Mid-Sprint Review' not found")
        else:
            checks_passed.append("[C] Mid-Sprint Review heading_2 found")

        # Check 5: Paragraph with sprint health status
        health_paragraph_found = False
        for block in sorted_blocks:
            if block.get("type") in ["paragraph", "text"]:
                content = block.get("content", "").lower()
                if "sprint health" in content and "green" in content:
                    health_paragraph_found = True
                    break

        if not health_paragraph_found:
            errors.append("[X] Paragraph with 'Sprint health: Green' not found")
        else:
            checks_passed.append("[C] Sprint health paragraph found")

        # Check 6: Todo with velocity chart update
        velocity_todo_found = False
        for block in sorted_blocks:
            if block.get("type") in ["todo", "to_do", "checkbox"]:
                content = block.get("content", "").lower()
                if "velocity chart" in content or "📈" in block.get("content", ""):
                    velocity_todo_found = True
                    break

        if not velocity_todo_found:
            errors.append("[X] Todo '📈 Update velocity chart in team dashboard' not found")
        else:
            checks_passed.append("[C] Velocity chart todo found")

        # Check 7: Checked todos end with '✓ DONE'
        done_todos_found = 0
        for block in sorted_blocks:
            if block.get("type") in ["todo", "to_do", "checkbox"]:
                content = block.get("content", "")
                properties = block.get("properties", {})
                is_checked = properties.get("checked", False)
            
                if is_checked and "done" in content.lower():
                    done_todos_found += 1

        if done_todos_found < 1:
            checks_passed.append("[C] Note: No checked todos with '✓ DONE' suffix found")
        else:
            checks_passed.append(f"[C] Found {done_todos_found} checked todos with DONE suffix")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: Weekly Standup Template Action Items
# =============================================================================
def _validate_weekly_standup_template_action_items(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Weekly Standup Template with Action Items section and todos."""
    errors: list[str] = []

    checks_passed = []

    # Find Weekly Standup Template page
    try:
        standup = _find_page_by_title(final_state_backend, "Weekly Standup Template")
        if not standup:
            errors.append("[X] Weekly Standup Template page not found")
        else:
            checks_passed.append("[C] Weekly Standup Template page found")

        page_id = standup.get("_id")
        page_blocks = _get_blocks_for_page(final_state_backend, page_id)
        sorted_blocks = sorted(page_blocks, key=lambda b: b.get("order", 0))
        checks_passed.append("[C] Weekly Standup Template page found")

        # Check 1: heading_2 '🎯 Action Items'
        action_items_heading_found = False
        action_items_idx = None
        for i, block in enumerate(sorted_blocks):
            if block.get("type") in ["heading2", "heading_2"]:
                content = block.get("content", "")
                if "🎯" in content and "action items" in content.lower():
                    action_items_heading_found = True
                    action_items_idx = i
                    break

        if not action_items_heading_found:
            errors.append("[X] heading_2 '🎯 Action Items' not found")
        else:
            checks_passed.append("[C] Action Items heading_2 found")

        # Check 2: Yellow callout with 48 hours text
        yellow_callout_found = False
        for block in sorted_blocks:
            if block.get("type") == "callout":
                properties = block.get("properties", {})
                bg_color = properties.get("backgroundColor", block.get("backgroundColor", ""))
                content = block.get("content", "").lower()
            
                has_yellow_bg = "yellow" in bg_color.lower() if bg_color else False
                has_48h_text = "48 hours" in content or "⚡" in block.get("content", "")
            
                if has_yellow_bg and has_48h_text:
                    yellow_callout_found = True
                    break

        if not yellow_callout_found:
            errors.append("[X] Yellow callout with '⚡ Action items must be resolved within 48 hours' not found")
        else:
            checks_passed.append("[C] Yellow callout with 48 hours text found")

        # Check 3: Three unchecked todos with specific texts
        expected_todos = ["send status update", "review and approve", "update project timeline"]
        todo_count = 0
    
        for block in sorted_blocks:
            if block.get("type") in ["todo", "to_do", "checkbox"]:
                content = block.get("content", "").lower()
                properties = block.get("properties", {})
                is_checked = properties.get("checked", False)
            
                if not is_checked:
                    for expected in expected_todos:
                        if expected in content:
                            todo_count += 1
                            break

        if todo_count < 3:
            errors.append(f"[X] Expected 3 unchecked todos with specific texts, found {todo_count}")
        else:
            checks_passed.append(f"[C] Found {todo_count} required unchecked todos")

        # Check 4: Divider after todos
        divider_found = False
        for block in sorted_blocks:
            if block.get("type") == "divider":
                divider_found = True
                break

        if not divider_found:
            errors.append("[X] Divider not found after todos")
        else:
            checks_passed.append("[C] Divider found")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: Getting Started Progress Tracker
# =============================================================================
def _validate_getting_started_progress_tracker(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Getting Started page with progress tracker, callout, and bookmarks."""
    errors: list[str] = []

    checks_passed = []

    # Find Getting Started page
    try:
        getting_started = _find_page_by_title(final_state_backend, "Getting Started")
        if not getting_started:
            errors.append("[X] Getting Started page not found")
        else:
            checks_passed.append("[C] Getting Started page found")

        page_id = getting_started.get("_id")
        page_blocks = _get_blocks_for_page(final_state_backend, page_id)
        sorted_blocks = sorted(page_blocks, key=lambda b: b.get("order", 0))
        checks_passed.append("[C] Getting Started page found")

        # Check 1: heading_2 '🎯 Onboarding Progress Tracker'
        tracker_heading_found = False
        for block in sorted_blocks:
            if block.get("type") in ["heading2", "heading_2"]:
                content = block.get("content", "")
                if "🎯" in content and "onboarding progress tracker" in content.lower():
                    tracker_heading_found = True
                    break

        if not tracker_heading_found:
            errors.append("[X] heading_2 '🎯 Onboarding Progress Tracker' not found")
        else:
            checks_passed.append("[C] Progress Tracker heading_2 found")

        # Check 2: Callout with appropriate color based on completion
        # Should be green if >50% complete, yellow otherwise
        callout_found = False
        for block in sorted_blocks:
            if block.get("type") == "callout":
                properties = block.get("properties", {})
                bg_color = properties.get("backgroundColor", block.get("backgroundColor", ""))
                content = block.get("content", "").lower()
            
                has_green_or_yellow = "green" in bg_color.lower() or "yellow" in bg_color.lower() if bg_color else False
                has_progress_text = "progress" in content or "going" in content or "halfway" in content
            
                if has_green_or_yellow and has_progress_text:
                    callout_found = True
                    break

        if not callout_found:
            errors.append("[X] Green or yellow callout with progress message not found")
        else:
            checks_passed.append("[C] Progress callout found")

        # Check 3: Divider exists
        divider_found = False
        for block in sorted_blocks:
            if block.get("type") == "divider":
                divider_found = True
                break

        if not divider_found:
            errors.append("[X] Divider not found")
        else:
            checks_passed.append("[C] Divider found")

        # Check 4: heading_3 '📚 Additional Resources'
        resources_heading_found = False
        for block in sorted_blocks:
            if block.get("type") in ["heading3", "heading_3"]:
                content = block.get("content", "")
                if "📚" in content and "additional resources" in content.lower():
                    resources_heading_found = True
                    break

        if not resources_heading_found:
            errors.append("[X] heading_3 '📚 Additional Resources' not found")
        else:
            checks_passed.append("[C] Additional Resources heading_3 found")

        # Check 5: Three bookmark blocks
        bookmark_count = sum(1 for b in sorted_blocks if b.get("type") == "bookmark")
        if bookmark_count < 3:
            errors.append(f"[X] Expected 3 bookmark blocks, found {bookmark_count}")
        else:
            checks_passed.append(f"[C] Found {bookmark_count} bookmark blocks")

        # Check 6: Quote block at end
        quote_found = False
        for block in sorted_blocks:
            if block.get("type") == "quote":
                content = block.get("content", "").lower()
                if "every expert was once a beginner" in content:
                    quote_found = True
                    break

        if not quote_found:
            errors.append("[X] Quote 'Remember: Every expert was once a beginner.' not found")
        else:
            checks_passed.append("[C] Motivational quote found")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: Brand Guidelines Move
# =============================================================================
def _validate_brand_guidelines_move(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Brand Guidelines moved under Design System with restructured content."""
    errors: list[str] = []

    checks_passed = []

    # Find Design System page
    try:
        design_system = _find_page_by_title(final_state_backend, "Design System")
        if not design_system:
            errors.append("[X] Design System page not found")
        else:
            checks_passed.append("[C] Design System page found")
    
        design_system_id = design_system.get("_id")
        checks_passed.append("[C] Design System page found")

        # Check 1: Brand Guidelines is now child of Design System
        brand_guidelines = None
        child_pages = _get_child_pages(final_state_backend, design_system_id)
        for child in child_pages:
            if "brand guidelines" in child.get("title", "").lower():
                brand_guidelines = child
                break
    
        if not brand_guidelines:
            errors.append("[X] Brand Guidelines not found as child of Design System")
        else:
            checks_passed.append("[C] Brand Guidelines found as child of Design System")
    
        page_id = brand_guidelines.get("_id")
        page_blocks = _get_blocks_for_page(final_state_backend, page_id)
        sorted_blocks = sorted(page_blocks, key=lambda b: b.get("order", 0))
        checks_passed.append("[C] Brand Guidelines is child of Design System")

        # Check 2: heading_1 '🏷️ Brand Guidelines' at top
        brand_heading_found = False
        for block in sorted_blocks[:5]:
            if block.get("type") in ["heading1", "heading_1"]:
                content = block.get("content", "")
                if "🏷️" in content and "brand guidelines" in content.lower():
                    brand_heading_found = True
                    break

        if not brand_heading_found:
            errors.append("[X] heading_1 '🏷️ Brand Guidelines' not found at top")
        else:
            checks_passed.append("[C] Brand Guidelines heading_1 found")

        # Check 3: Blue callout with 📍 icon and relocation note
        blue_callout_found = False
        for block in sorted_blocks:
            if block.get("type") == "callout":
                properties = block.get("properties", {})
                bg_color = properties.get("backgroundColor", block.get("backgroundColor", ""))
                icon = properties.get("icon", block.get("icon", ""))
                content = block.get("content", "").lower()
            
                has_blue_bg = "blue" in bg_color.lower() if bg_color else False
                has_pin_icon = "📍" in icon if icon else False
                has_relocation_text = "relocated" in content or "design system" in content
            
                if has_blue_bg and has_pin_icon and has_relocation_text:
                    blue_callout_found = True
                    break

        if not blue_callout_found:
            errors.append("[X] Blue callout with 📍 icon and relocation note not found")
        else:
            checks_passed.append("[C] Blue relocation callout found")

        # Check 4: heading_2 '🎨 Brand Elements'
        brand_elements_found = False
        for block in sorted_blocks:
            if block.get("type") in ["heading2", "heading_2"]:
                content = block.get("content", "")
                if "🎨" in content and "brand elements" in content.lower():
                    brand_elements_found = True
                    break

        if not brand_elements_found:
            errors.append("[X] heading_2 '🎨 Brand Elements' not found")
        else:
            checks_passed.append("[C] Brand Elements heading_2 found")

        # Check 5: Numbered list with 4 items
        numbered_items = [b for b in sorted_blocks if b.get("type") in ["numberedList", "numbered_list", "numbered_list_item", "numbered"]]
        if len(numbered_items) < 4:
            errors.append(f"[X] Expected 4 numbered list items, found {len(numbered_items)}")
        else:
            checks_passed.append(f"[C] Found {len(numbered_items)} numbered list items")

        # Check 6: heading_2 '📚 Related Resources'
        resources_heading_found = False
        for block in sorted_blocks:
            if block.get("type") in ["heading2", "heading_2"]:
                content = block.get("content", "")
                if "📚" in content and "related resources" in content.lower():
                    resources_heading_found = True
                    break

        if not resources_heading_found:
            errors.append("[X] heading_2 '📚 Related Resources' not found")
        else:
            checks_passed.append("[C] Related Resources heading_2 found")

        # Check 7: Page icon changed to 📘
        page_icon = brand_guidelines.get("icon", "")
        if "📘" in page_icon:
            checks_passed.append("[C] Page icon updated to 📘")
        else:
            checks_passed.append("[C] Note: Page icon may not be 📘")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: Onboarding Guide Restructure with TOC
# =============================================================================
def _validate_onboarding_guide_restructure_toc(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Onboarding Guide with welcome callout, TOC, and completion metrics."""
    errors: list[str] = []

    checks_passed = []

    # Find Onboarding Guide page
    try:
        onboarding = _find_page_by_title(final_state_backend, "Onboarding Guide")
        if not onboarding:
            errors.append("[X] Onboarding Guide page not found")
        else:
            checks_passed.append("[C] Onboarding Guide page found")

        page_id = onboarding.get("_id")
        page_blocks = _get_blocks_for_page(final_state_backend, page_id)
        sorted_blocks = sorted(page_blocks, key=lambda b: b.get("order", 0))
        checks_passed.append("[C] Onboarding Guide page found")

        # Check 1: Welcome callout at the very beginning with 👋 icon
        welcome_callout_found = False
        for block in sorted_blocks[:5]:  # Check first few blocks
            if block.get("type") == "callout":
                properties = block.get("properties", {})
                icon = properties.get("icon", block.get("icon", ""))
                content = block.get("content", "").lower()
            
                has_wave_icon = "👋" in icon if icon else False
                has_welcome_text = "welcome" in content and "sections" in content
            
                if has_wave_icon and has_welcome_text:
                    welcome_callout_found = True
                    break

        if not welcome_callout_found:
            errors.append("[X] Welcome callout with 👋 icon not found at beginning")
        else:
            checks_passed.append("[C] Welcome callout found at beginning")

        # Check 2: heading_2 '📍 Table of Contents'
        toc_heading_found = False
        for block in sorted_blocks:
            if block.get("type") in ["heading2", "heading_2"]:
                content = block.get("content", "")
                if "📍" in content and "table of contents" in content.lower():
                    toc_heading_found = True
                    break

        if not toc_heading_found:
            errors.append("[X] heading_2 '📍 Table of Contents' not found")
        else:
            checks_passed.append("[C] Table of Contents heading_2 found")

        # Check 3: Numbered list for TOC
        numbered_items = [b for b in sorted_blocks if b.get("type") in ["numberedList", "numbered_list", "numbered_list_item", "numbered"]]
        if len(numbered_items) < 1:
            errors.append("[X] Numbered list for TOC not found")
        else:
            checks_passed.append(f"[C] Found {len(numbered_items)} TOC items")

        # Check 4: heading_3 '📈 Guide Completion Metrics' at end
        metrics_heading_found = False
        for block in sorted_blocks:
            if block.get("type") in ["heading3", "heading_3"]:
                content = block.get("content", "")
                if "📈" in content and "guide completion metrics" in content.lower():
                    metrics_heading_found = True
                    break

        if not metrics_heading_found:
            errors.append("[X] heading_3 '📈 Guide Completion Metrics' not found")
        else:
            checks_passed.append("[C] Guide Completion Metrics heading_3 found")

        # Check 5: Paragraph with total tasks and completion rate
        metrics_paragraph_found = False
        for block in sorted_blocks:
            if block.get("type") in ["paragraph", "text"]:
                content = block.get("content", "").lower()
                if "total tasks" in content and "%" in content:
                    metrics_paragraph_found = True
                    break

        if not metrics_paragraph_found:
            errors.append("[X] Paragraph with 'Total tasks' and completion rate not found")
        else:
            checks_passed.append("[C] Metrics paragraph found")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: Architecture Overview under Engineering Wiki
# =============================================================================
def _validate_architecture_overview_engineering_wiki(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Architecture Overview page created under Engineering Wiki."""
    errors: list[str] = []

    checks_passed = []

    # Find Engineering Wiki page
    try:
        eng_wiki = _find_page_by_title(final_state_backend, "Engineering Wiki")
        if not eng_wiki:
            errors.append("[X] Engineering Wiki page not found")
        else:
            checks_passed.append("[C] Engineering Wiki page found")
    
        eng_wiki_id = eng_wiki.get("_id")
        checks_passed.append("[C] Engineering Wiki page found")

        # Check 1: Architecture Overview is child of Engineering Wiki
        arch_overview = None
        child_pages = _get_child_pages(final_state_backend, eng_wiki_id)
        for child in child_pages:
            if "architecture overview" in child.get("title", "").lower():
                arch_overview = child
                break
    
        if not arch_overview:
            errors.append("[X] Architecture Overview not found as child of Engineering Wiki")
        else:
            checks_passed.append("[C] Architecture Overview found as child of Engineering Wiki")
    
        page_id = arch_overview.get("_id")
        page_blocks = _get_blocks_for_page(final_state_backend, page_id)
        sorted_blocks = sorted(page_blocks, key=lambda b: b.get("order", 0))
        checks_passed.append("[C] Architecture Overview is child of Engineering Wiki")

        # Check 2: heading_1 '🏗️ Architecture Overview'
        arch_heading_found = False
        for block in sorted_blocks:
            if block.get("type") in ["heading1", "heading_1"]:
                content = block.get("content", "")
                if "🏗️" in content and "architecture overview" in content.lower():
                    arch_heading_found = True
                    break

        if not arch_heading_found:
            errors.append("[X] heading_1 '🏗️ Architecture Overview' not found")
        else:
            checks_passed.append("[C] Architecture Overview heading_1 found")

        # Check 3: Quote block with architecture quote
        quote_found = False
        for block in sorted_blocks:
            if block.get("type") == "quote":
                content = block.get("content", "").lower()
                if "architecture" in content or "decisions not made" in content:
                    quote_found = True
                    break

        if not quote_found:
            errors.append("[X] Quote block about architecture not found")
        else:
            checks_passed.append("[C] Architecture quote found")

        # Check 4: heading_2 '📋 Architecture Components'
        components_heading_found = False
        for block in sorted_blocks:
            if block.get("type") in ["heading2", "heading_2"]:
                content = block.get("content", "")
                if "📋" in content and "architecture components" in content.lower():
                    components_heading_found = True
                    break

        if not components_heading_found:
            errors.append("[X] heading_2 '📋 Architecture Components' not found")
        else:
            checks_passed.append("[C] Architecture Components heading_2 found")

        # Check 5: Numbered list with architecture pages
        numbered_items = [b for b in sorted_blocks if b.get("type") in ["numberedList", "numbered_list", "numbered_list_item", "numbered"]]
        if len(numbered_items) < 1:
            errors.append("[X] Numbered list of architecture pages not found")
        else:
            checks_passed.append(f"[C] Found {len(numbered_items)} numbered list items")

        # Check 6: heading_2 '🔗 Quick Links'
        quick_links_found = False
        for block in sorted_blocks:
            if block.get("type") in ["heading2", "heading_2"]:
                content = block.get("content", "")
                if "🔗" in content and "quick links" in content.lower():
                    quick_links_found = True
                    break

        if not quick_links_found:
            errors.append("[X] heading_2 '🔗 Quick Links' not found")
        else:
            checks_passed.append("[C] Quick Links heading_2 found")

        # Check 7: Bookmark blocks
        bookmark_count = sum(1 for b in sorted_blocks if b.get("type") == "bookmark")
        if bookmark_count < 2:
            errors.append(f"[X] Expected at least 2 bookmark blocks, found {bookmark_count}")
        else:
            checks_passed.append(f"[C] Found {bookmark_count} bookmark blocks")

        # Check 8: Divider exists
        divider_found = any(b.get("type") == "divider" for b in sorted_blocks)
        if not divider_found:
            errors.append("[X] Divider not found")
        else:
            checks_passed.append("[C] Divider found")

        # Check 9: Final paragraph with date and count
        final_paragraph_found = False
        for block in sorted_blocks:
            if block.get("type") in ["paragraph", "text"]:
                content = block.get("content", "").lower()
                if "generated on" in content or "total architecture pages" in content:
                    final_paragraph_found = True
                    break

        if not final_paragraph_found:
            errors.append("[X] Final paragraph with date and page count not found")
        else:
            checks_passed.append("[C] Final paragraph with date and count found")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: Onboarding Guide 30-Day Milestones
# =============================================================================
def _validate_onboarding_guide_milestones(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Onboarding Guide with 30-Day Milestones section and six todos."""
    errors: list[str] = []

    checks_passed = []

    # Find Onboarding Guide page
    try:
        onboarding = _find_page_by_title(final_state_backend, "Onboarding Guide")
        if not onboarding:
            errors.append("[X] Onboarding Guide page not found")
        else:
            checks_passed.append("[C] Onboarding Guide page found")

        page_id = onboarding.get("_id")
        page_blocks = _get_blocks_for_page(final_state_backend, page_id)
        sorted_blocks = sorted(page_blocks, key=lambda b: b.get("order", 0))
        checks_passed.append("[C] Onboarding Guide page found")

        # Check 1: heading_2 '📋 30-Day Milestones'
        milestones_heading_found = False
        milestones_idx = None
        for i, block in enumerate(sorted_blocks):
            if block.get("type") in ["heading2", "heading_2"]:
                content = block.get("content", "")
                if "📋" in content and "30-day milestones" in content.lower():
                    milestones_heading_found = True
                    milestones_idx = i
                    break

        if not milestones_heading_found:
            errors.append("[X] heading_2 '📋 30-Day Milestones' not found")
        else:
            checks_passed.append("[C] 30-Day Milestones heading_2 found")

        # Check 2: Six unchecked todos with specific emojis
        expected_emojis = ["🎯", "👥", "💻", "📝", "🔍", "🚀"]
        todo_count = 0
    
        for block in sorted_blocks:
            if block.get("type") in ["todo", "to_do", "checkbox"]:
                content = block.get("content", "")
                properties = block.get("properties", {})
                is_checked = properties.get("checked", False)
            
                if not is_checked:
                    for emoji in expected_emojis:
                        if emoji in content:
                            todo_count += 1
                            break

        if todo_count < 6:
            errors.append(f"[X] Expected 6 unchecked todos with specific emojis, found {todo_count}")
        else:
            checks_passed.append(f"[C] Found {todo_count} milestone todos")

        # Check 3: Divider after todos
        divider_found = False
        for block in sorted_blocks:
            if block.get("type") == "divider":
                divider_found = True
                break

        if not divider_found:
            errors.append("[X] Divider not found after todos")
        else:
            checks_passed.append("[C] Divider found")

        # Check 4: Paragraph with reminder text
        reminder_found = False
        for block in sorted_blocks:
            if block.get("type") in ["paragraph", "text"]:
                content = block.get("content", "").lower()
                if "quality over quantity" in content or "understanding our systems" in content:
                    reminder_found = True
                    break

        if not reminder_found:
            errors.append("[X] Paragraph with 'Quality over quantity' reminder not found")
        else:
            checks_passed.append("[C] Reminder paragraph found")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: Project Guidelines Quick Reference
# =============================================================================
def _validate_project_guidelines_quick_reference(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Project Guidelines with dividers, updated icons, and quick reference section."""
    errors: list[str] = []

    checks_passed = []

    # Find Project Guidelines page
    try:
        guidelines = _find_page_by_title(final_state_backend, "Project Guidelines & Best Practices")
        if not guidelines:
            guidelines = _find_page_by_title(final_state_backend, "Project Guidelines")
        if not guidelines:
            errors.append("[X] Project Guidelines page not found")
        else:
            checks_passed.append("[C] Project Guidelines page found")

        page_id = guidelines.get("_id")
        page_blocks = _get_blocks_for_page(final_state_backend, page_id)
        sorted_blocks = sorted(page_blocks, key=lambda b: b.get("order", 0))
        checks_passed.append("[C] Project Guidelines page found")

        # Check 1: heading_1 '📝 Quick Reference' at the very beginning
        quick_ref_heading_found = False
        quick_ref_idx = None
        for i, block in enumerate(sorted_blocks[:10]):
            if block.get("type") in ["heading1", "heading_1"]:
                content = block.get("content", "")
                if "📝" in content and "quick reference" in content.lower():
                    quick_ref_heading_found = True
                    quick_ref_idx = i
                    break

        if not quick_ref_heading_found:
            errors.append("[X] heading_1 '📝 Quick Reference' not found at beginning")
        else:
            checks_passed.append("[C] Quick Reference heading_1 found at beginning")

        # Check 2: Numbered list summarizing callouts
        numbered_items = [b for b in sorted_blocks if b.get("type") in ["numberedList", "numbered_list", "numbered_list_item", "numbered"]]
        if len(numbered_items) < 1:
            errors.append("[X] Numbered list summarizing callouts not found")
        else:
            checks_passed.append(f"[C] Found {len(numbered_items)} numbered list items")

        # Check 3: Dividers exist (before yellow callouts)
        divider_count = sum(1 for b in sorted_blocks if b.get("type") == "divider")
        if divider_count < 1:
            errors.append("[X] No dividers found")
        else:
            checks_passed.append(f"[C] Found {divider_count} dividers")

        # Check 4: Red callout with ⛔ icon (changed from 🚨)
        red_callout_with_stop_icon = False
        for block in sorted_blocks:
            if block.get("type") == "callout":
                properties = block.get("properties", {})
                bg_color = properties.get("backgroundColor", block.get("backgroundColor", ""))
                icon = properties.get("icon", block.get("icon", ""))
                content = block.get("content", "").lower()
            
                has_red_bg = "red" in bg_color.lower() if bg_color else False
                has_stop_icon = "⛔" in icon if icon else False
                has_critical_text = "critical" in content
            
                if has_red_bg and has_stop_icon and has_critical_text:
                    red_callout_with_stop_icon = True
                    break

        if not red_callout_with_stop_icon:
            errors.append("[X] Red callout with ⛔ icon and 'Critical:' text not found")
        else:
            checks_passed.append("[C] Red callout with ⛔ icon found")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

    # -----------------------------------------------------------------------------
    # reorganize-engineering-documentation-v2
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_reorganize_engineering_documentation(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Task: Reorganize engineering documentation pages under a new hub page.
    
    Validates:
    1. "Technical Documentation Hub" page exists
    2. All non-archived pages with "API" or "Engineering" in title have the hub as parent
    3. API Documentation page content references the new structure
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    # 1. Find "Technical Documentation Hub" page
    try:
        hub_results = final_state_backend.query({
            "collection": "pages", 
            "filter": {"title": "Technical Documentation Hub"}
        })
    
        if not hub_results or len(hub_results) == 0:
            errors.append("[X] Page 'Technical Documentation Hub' not found")
        else:
            checks_passed.append("[C] Page 'Technical Documentation Hub' found")
    
        hub_page = hub_results[0]
        hub_page_id = hub_page.get("_id")
    
        if not hub_page_id:
            errors.append("[X] Technical Documentation Hub page has no _id")
        else:
            checks_passed.append("[C] Technical Documentation Hub page has _id")
    
        # 2. Find all non-archived pages with "API" or "Engineering" in title
        # Use regex to find pages (avoids text index timing issues)
        all_pages = final_state_backend.query({
            "collection": "pages",
            "filter": {"$or": [
                {"title": {"$regex": "API"}},
                {"title": {"$regex": "Engineering"}}
            ]}
        })
    
        engineering_pages = [
            page for page in all_pages 
            if ("API" in page.get("title", "") or "Engineering" in page.get("title", ""))
            and not page.get("isArchived", False)
            and page.get("_id") != hub_page_id  # Exclude hub itself
        ]
    
        if not engineering_pages:
            errors.append("[X] No pages found with 'API' or 'Engineering' in title")
        else:
            checks_passed.append("[C] pages found with 'API' or 'Engineering' in title")
    
        # Check if all engineering pages have hub as parent
        misparented = []
        for page in engineering_pages:
            if page.get("parentId") != hub_page_id:
                misparented.append(page.get("title", "Unknown"))
    
        if misparented:
            errors.append(f"[X] Pages not under hub: {', '.join(misparented)}")
        else:
            checks_passed.append(f"[C] Pages under hub: {', '.join(misparented)}")
    
        # 3. Check API Documentation page references the hub
        api_results = final_state_backend.query({
            "collection": "pages", 
            "filter": {"title": "API Documentation"}
        })
    
        if not api_results:
            errors.append("[X] API Documentation page not found")
        else:
            checks_passed.append("[C] API Documentation page found")
    
        api_page = api_results[0]
        content_blocks = final_state_backend.query({
            "collection": "blocks",
            "filter": {"pageId": api_page.get("_id")}
        })
    
        # Check if any content block mentions the hub
        hub_mentioned = False
        for block in content_blocks:
            # Check various possible text fields in blocks
            block_text = str(block.get("text", "") or block.get("content", "") or block.get("value", ""))
            if "Technical Documentation Hub" in block_text:
                hub_mentioned = True
                break
    
        if not hub_mentioned:
            errors.append("[X] API Documentation page does not reference 'Technical Documentation Hub'")
        else:
            checks_passed.append("[C] API Documentation page reference 'Technical Documentation Hub'")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

    # -----------------------------------------------------------------------------
    # create-documentation-center-hub
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_create_documentation_center_hub(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Task: Create comprehensive documentation hub with organized sections.
    
    Validates:
    1. "Documentation Center" page exists with books icon and is marked as favorite
    2. Contains 3 main section pages
    3. "API Documentation" and "Engineering Wiki" are moved under Technical Docs section
    4. "Process Guides" and "Quick References" pages exist with structured content
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    # 1. Find "Documentation Center" page
    try:
        doc_center_results = final_state_backend.query({
            "collection": "pages",
            "filter": {"title": "Documentation Center"}
        })
    
        if not doc_center_results or len(doc_center_results) == 0:
            errors.append("[X] Page 'Documentation Center' not found")
        else:
            checks_passed.append("[C] Page 'Documentation Center' found")
    
        doc_center = doc_center_results[0]
        doc_center_id = doc_center.get("_id")
    
        # Check books icon
        if doc_center.get("icon") != "📚":
            errors.append("[X] Documentation Center does not have books icon")
        else:
            checks_passed.append("[C] Documentation Center has books icon")
    
        # Check if marked as favorite (backend is source of truth)
        if not doc_center.get("isFavorite", False):
            errors.append("[X] Documentation Center is not marked as favorite")
        else:
            checks_passed.append("[C] Documentation Center is marked as favorite")
    
        # 2. Find children of Documentation Center
        doc_center_children = final_state_backend.query({
            "collection": "pages",
            "filter": {"parentId": doc_center_id}
        })
    
        if len(doc_center_children) < 3:
            errors.append(f"[X] Documentation Center has {len(doc_center_children)} children, expected at least 3 main sections")
        else:
            checks_passed.append(f"[C] Documentation Center has {len(doc_center_children)} children, expected at least 3 main sections")
    
        # 3. Find "Technical Docs" section
        tech_docs_results = final_state_backend.query({
            "collection": "pages",
            "filter": {"title": "Technical Docs", "parentId": doc_center_id}
        })
        if not tech_docs_results:
            errors.append("[X] Technical Docs section not found under Documentation Center")
        else:
            checks_passed.append("[C] Technical Docs section found under Documentation Center")
    
        tech_docs_id = tech_docs_results[0].get("_id")
    
        # 4. Check if API Documentation and Engineering Wiki are under Technical Docs
        api_doc_results = final_state_backend.query({
            "collection": "pages",
            "filter": {"title": "API Documentation"}
        })
    
        eng_wiki_results = final_state_backend.query({
            "collection": "pages",
            "filter": {"title": "Engineering Wiki"}
        })
    
        if not api_doc_results:
            errors.append("[X] API Documentation page not found")
        else:
            checks_passed.append("[C] API Documentation page found")
    
        if not eng_wiki_results:
            errors.append("[X] Engineering Wiki page not found")
        else:
            checks_passed.append("[C] Engineering Wiki page found")
    
        if api_doc_results[0].get("parentId") != tech_docs_id:
            errors.append("[X] API Documentation is not under Technical Docs section")
        else:
            checks_passed.append("[C] API Documentation is under Technical Docs section")
    
        if eng_wiki_results[0].get("parentId") != tech_docs_id:
            errors.append("[X] Engineering Wiki is not under Technical Docs section")
        else:
            checks_passed.append("[C] Engineering Wiki is under Technical Docs section")
    
        # 5. Check for Process Guides page with content
        process_guides_results = final_state_backend.query({
            "collection": "pages",
            "filter": {"title": "Process Guides"}
        })
    
        if not process_guides_results:
            errors.append("[X] Process Guides page not found")
        else:
            checks_passed.append("[C] Process Guides page found")
    
        process_guides = process_guides_results[0]
        content_blocks = final_state_backend.query({
            "collection": "blocks",
            "filter": {"pageId": process_guides.get("_id")}
        })
    
        # Check for numbered lists and callouts
        has_numbered_list = any(block.get("type") == "numberedList" for block in content_blocks)
        has_callout = any(block.get("type") == "callout" for block in content_blocks)
    
        if not (has_numbered_list or has_callout):
            errors.append("[X] Process Guides page does not have structured content (numbered lists or callouts)")
        else:
            checks_passed.append("[C] Process Guides page has structured content (numbered lists or callouts)")
    
        # 6. Check for Quick References page
        quick_ref_results = final_state_backend.query({
            "collection": "pages",
            "filter": {"title": "Quick References"}
        })
    
        if not quick_ref_results:
            errors.append("[X] Quick References page not found")
        else:
            checks_passed.append("[C] Quick References page found")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

    # -----------------------------------------------------------------------------
    # create-meeting-notes-template-2025
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_create_meeting_notes_template_2025(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Task: Create improved meeting notes template with structured content.
    
    Validates:
    1. New "Meeting Notes Template - 2025" page created
    2. Template contains heading1, bulletedList, numberedList, and todo blocks
    3. Template is child of main "Meeting Notes" page
    4. Template marked as favorite
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    # 1. Find "Meeting Notes Template - 2025" page
    try:
        template_results = final_state_backend.query({
            "collection": "pages",
            "filter": {"title": "Meeting Notes Template - 2025"}
        })
    
        if not template_results or len(template_results) == 0:
            errors.append("[X] Page 'Meeting Notes Template - 2025' not found")
        else:
            checks_passed.append("[C] Page 'Meeting Notes Template - 2025' found")
    
        template_page = template_results[0]
        template_id = template_page.get("_id")
    
        # 2. Check if marked as favorite (check backend isFavorite field)
        if not template_page.get("isFavorite", False):
            errors.append("[X] Meeting Notes Template - 2025 is not marked as favorite")
        else:
            checks_passed.append("[C] Meeting Notes Template - 2025 is marked as favorite")
    
        # 3. Check content blocks for required types
        content_blocks = final_state_backend.query({
            "collection": "blocks",
            "filter": {"pageId": template_page.get("_id")}
        })
    
        block_types = [block.get("type") for block in content_blocks]
    
        required_types = ["heading1", "bulletedList", "numberedList", "todo"]
        missing_types = []
    
        for req_type in required_types:
            if req_type not in block_types:
                missing_types.append(req_type)
    
        if missing_types:
            errors.append(f"[X] Template missing required block types: {', '.join(missing_types)}")
        else:
            checks_passed.append(f"[C] Template has required block types: {', '.join(missing_types)}")
    
        # 4. Check if template is child of "Meeting Notes" page
        parent_id = template_page.get("parentId")
        if not parent_id:
            errors.append("[X] Template has no parent page")
        else:
            checks_passed.append("[C] Template has parent page")
    
        parent_results = final_state_backend.query({
            "collection": "pages",
            "filter": {"_id": parent_id}
        })
    
        if not parent_results:
            errors.append("[X] Template's parent page not found")
        else:
            checks_passed.append("[C] Template's parent page found")
    
        parent_page = parent_results[0]
        if "Meeting Notes" not in parent_page.get("title", ""):
            errors.append(f"[X] Template is not under 'Meeting Notes' page (parent: {parent_page.get('title', 'Unknown')})")
        else:
            checks_passed.append(f"[C] Template is under 'Meeting Notes' page (parent: {parent_page.get('title', 'Unknown')})")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

    # -----------------------------------------------------------------------------
    # streamline-meeting-documentation
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_streamline_meeting_documentation(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Task: Archive old meeting pages and reorganize meeting structure.
    
    Validates:
    1. "Q1 2024 Meeting Archive" page created
    2. At least 1 old meeting page moved into archive
    3. New "Current Meetings" page created
    4. Original page retitled to "Meeting Hub" with calendar icon
    5. Archive and current pages properly positioned in hierarchy
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    # 1. Find "Meeting Hub" page (renamed from "Meeting Notes")
    try:
        hub_results = final_state_backend.query({
            "collection": "pages",
            "filter": {"title": "Meeting Hub"}
        })
    
        if not hub_results or len(hub_results) == 0:
            errors.append("[X] Page 'Meeting Hub' not found")
        else:
            checks_passed.append("[C] Page 'Meeting Hub' found")
    
        hub_page = hub_results[0]
        hub_id = hub_page.get("_id")
    
        # Check calendar icon
        if hub_page.get("icon") != "📅":
            errors.append("[X] Meeting Hub does not have calendar icon")
        else:
            checks_passed.append("[C] Meeting Hub has calendar icon")
    
        # 2. Find "Q1 2024 Meeting Archive" page
        archive_results = final_state_backend.query({
            "collection": "pages",
            "filter": {"title": "Q1 2024 Meeting Archive"}
        })
    
        if not archive_results or len(archive_results) == 0:
            errors.append("[X] Page 'Q1 2024 Meeting Archive' not found")
        else:
            checks_passed.append("[C] Page 'Q1 2024 Meeting Archive' found")
    
        archive_page = archive_results[0]
        archive_id = archive_page.get("_id")
    
        # 3. Check if archive has children (moved meeting pages)
        archive_children = final_state_backend.query({
            "collection": "pages",
            "filter": {"parentId": archive_id}
        })
    
        if len(archive_children) < 1:
            errors.append("[X] No meeting pages moved into Q1 2024 Meeting Archive")
        else:
            checks_passed.append("[C] meeting pages moved into Q1 2024 Meeting Archive")
    
        # 4. Find "Current Meetings" page
        current_results = final_state_backend.query({
            "collection": "pages",
            "filter": {"title": "Current Meetings"}
        })
    
        if not current_results or len(current_results) == 0:
            errors.append("[X] Page 'Current Meetings' not found")
        else:
            checks_passed.append("[C] Page 'Current Meetings' found")
    
        current_page = current_results[0]
    
        # 5. Verify hierarchy - archive and current should be siblings under same parent
        archive_parent = archive_page.get("parentId")
        current_parent = current_page.get("parentId")
    
        if archive_parent != current_parent:
            errors.append("[X] Archive and Current Meetings pages are not siblings in hierarchy")
        else:
            checks_passed.append("[C] Archive and Current Meetings pages are siblings in hierarchy")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

    # -----------------------------------------------------------------------------
    # create-sprint-kickoff-template
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_create_sprint_kickoff_template(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Task: Customize sprint planning template with structured content.
    
    Validates:
    1. New page "Sprint Kickoff Template" exists with rocket icon
    2. Page is a child of "Project Documentation"
    3. Contains 2 main heading blocks, 1 numbered list with 3-4 items, and 1 todo checklist with 3 specific items
    4. Original "Weekly Standup Template" remains unchanged
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    # 1. Find "Sprint Kickoff Template" page
    try:
        template_results = final_state_backend.query({
            "collection": "pages",
            "filter": {"title": "Sprint Kickoff Template"}
        })
    
        if not template_results or len(template_results) == 0:
            errors.append("[X] Page 'Sprint Kickoff Template' not found")
        else:
            checks_passed.append("[C] Page 'Sprint Kickoff Template' found")
    
        template_page = template_results[0]
    
        # Check rocket icon
        if template_page.get("icon") != "🚀":
            errors.append("[X] Sprint Kickoff Template does not have rocket icon")
        else:
            checks_passed.append("[C] Sprint Kickoff Template has rocket icon")
    
        # 2. Check if template is child of "Project Documentation"
        parent_id = template_page.get("parentId")
        if not parent_id:
            errors.append("[X] Template has no parent page")
        else:
            checks_passed.append("[C] Template has parent page")
    
        parent_results = final_state_backend.query({
            "collection": "pages",
            "filter": {"_id": parent_id}
        })
    
        if not parent_results:
            errors.append("[X] Template's parent page not found")
        else:
            checks_passed.append("[C] Template's parent page found")
    
        parent_page = parent_results[0]
        if "Project Documentation" not in parent_page.get("title", ""):
            errors.append(f"[X] Template is not under 'Project Documentation' page (parent: {parent_page.get('title', 'Unknown')})")
        else:
            checks_passed.append(f"[C] Template is under 'Project Documentation' page (parent: {parent_page.get('title', 'Unknown')})")
    
        # 3. Check content structure
        content_blocks = final_state_backend.query({
            "collection": "blocks",
            "filter": {"pageId": template_page.get("_id")}
        })
    
        # Count heading blocks
        heading_blocks = [b for b in content_blocks if b.get("type") in ["heading1", "heading2", "heading3"]]
        if len(heading_blocks) < 2:
            errors.append(f"[X] Template has {len(heading_blocks)} heading blocks, expected at least 2")
        else:
            checks_passed.append(f"[C] Template has {len(heading_blocks)} heading blocks, expected at least 2")
    
        # Check for numbered list with 3-4 items
        numbered_lists = [b for b in content_blocks if b.get("type") == "numberedList"]
        if not numbered_lists:
            errors.append("[X] Template does not contain a numbered list")
        else:
            checks_passed.append("[C] Template does contains a numbered list")
    
        # Numbered list should have 3-4 items (check if there are multiple consecutive numbered list blocks)
        numbered_list_count = len(numbered_lists)
        if numbered_list_count < 3 or numbered_list_count > 4:
            # Be flexible - could be a single block with multiple items or multiple blocks
            if numbered_list_count < 1:
                errors.append("[X] Template numbered list should have 3-4 items")
            else:
                checks_passed.append("[C] Template numbered list should have 3-4 items")
    
        # Check for todo blocks with specific items
        todo_blocks = [b for b in content_blocks if b.get("type") == "todo"]
        if len(todo_blocks) < 3:
            errors.append(f"[X] Template has {len(todo_blocks)} todo items, expected at least 3")
        else:
            checks_passed.append(f"[C] Template has {len(todo_blocks)} todo items, expected at least 3")
    
        # Check for specific todo items
        todo_texts = [str(b.get("text", "") or b.get("content", "")).lower() for b in todo_blocks]
        required_todos = ["review backlog", "assign story points", "set sprint deadline"]
    
        missing_todos = []
        for req_todo in required_todos:
            if not any(req_todo in text for text in todo_texts):
                missing_todos.append(req_todo)
    
        if missing_todos:
            errors.append(f"[X] Template missing required todo items: {', '.join(missing_todos)}")
        else:
            checks_passed.append(f"[C] Template has required todo items: {', '.join(missing_todos)}")
    
        # 4. Verify "Weekly Standup Template" still exists unchanged
        standup_results = final_state_backend.query({
            "collection": "pages",
            "filter": {"title": "Weekly Standup Template"}
        })
    
        if not standup_results:
            errors.append("[X] Original 'Weekly Standup Template' page not found or was modified")
        else:
            checks_passed.append("[C] Original 'Weekly Standup Template' page found or was modified")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

    # -----------------------------------------------------------------------------
    # create-team-onboarding-guide
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_create_team_onboarding_guide(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Task: Create comprehensive onboarding guide with main page and sub-pages.
    
    Validates:
    1. "Team Onboarding" page exists with wave emoji and is marked as favorite
    2. Contains 3 child pages: First Day Checklist, Resources & Tools, Company Culture
    3. First Day Checklist has todo blocks
    4. Company Culture has quote blocks
    5. At least 8 total blocks across all pages
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    # 1. Find "Team Onboarding" page
    try:
        onboarding_results = final_state_backend.query({
            "collection": "pages",
            "filter": {"title": "Team Onboarding"}
        })
    
        if not onboarding_results:
            errors.append("[X] Page 'Team Onboarding' not found")
        else:
            checks_passed.append("[C] Page 'Team Onboarding' found")
    
        onboarding_page = onboarding_results[0]
        onboarding_id = onboarding_page.get("_id")
    
        # Check wave emoji
        if onboarding_page.get("icon") != "👋":
            errors.append("[X] Team Onboarding does not have wave emoji")
        else:
            checks_passed.append("[C] Team Onboarding has wave emoji")
    
        # Check if marked as favorite
        if not onboarding_page.get("isFavorite", False):
            errors.append("[X] Team Onboarding is not marked as favorite")
        else:
            checks_passed.append("[C] Team Onboarding is marked as favorite")
    
        # 2. Find children of Team Onboarding
        onboarding_children = final_state_backend.query({
            "collection": "pages",
            "filter": {"parentId": onboarding_id}
        })
    
        if len(onboarding_children) < 3:
            errors.append(f"[X] Team Onboarding has {len(onboarding_children)} children, expected at least 3")
        else:
            checks_passed.append(f"[C] Team Onboarding has {len(onboarding_children)} children, expected at least 3")
    
        # 3. Check for specific child pages
        child_titles = [child.get("title", "") for child in onboarding_children]
        required_pages = ["First Day Checklist", "Resources & Tools", "Company Culture"]
        missing_pages = [page for page in required_pages if page not in child_titles]
    
        if missing_pages:
            errors.append(f"[X] Missing required sub-pages: {', '.join(missing_pages)}")
        else:
            checks_passed.append(f"[C] has required sub-pages: {', '.join(missing_pages)}")
    
        # 4. Check First Day Checklist has todo blocks
        checklist_page = next((p for p in onboarding_children if p.get("title") == "First Day Checklist"), None)
        if checklist_page:
            checklist_blocks = final_state_backend.query({
                "collection": "blocks",
                "filter": {"pageId": checklist_page.get("_id")}
            })
            has_todo = any(block.get("type") == "todo" for block in checklist_blocks)
            if not has_todo:
                errors.append("[X] First Day Checklist does not have todo blocks")
            else:
                checks_passed.append("[C] First Day Checklist has todo blocks")
    
        # 5. Check Company Culture has quote blocks
        culture_page = next((p for p in onboarding_children if p.get("title") == "Company Culture"), None)
        if culture_page:
            culture_blocks = final_state_backend.query({
                "collection": "blocks",
                "filter": {"pageId": culture_page.get("_id")}
            })
            has_quote = any(block.get("type") == "quote" for block in culture_blocks)
            if not has_quote:
                errors.append("[X] Company Culture does not have quote blocks")
            else:
                checks_passed.append("[C] Company Culture has quote blocks")
    
        # 6. Count total blocks across all pages
        onboarding_blocks = final_state_backend.query({
            "collection": "blocks",
            "filter": {"pageId": onboarding_page.get("_id")}
        })
        total_blocks = len(onboarding_blocks)
        for child in onboarding_children:
            child_blocks = final_state_backend.query({
                "collection": "blocks",
                "filter": {"pageId": child.get("_id")}
            })
            total_blocks += len(child_blocks)
    
        if total_blocks < 8:
            errors.append(f"[X] Total blocks across all pages is {total_blocks}, expected at least 8")
        else:
            checks_passed.append(f"[C] Total blocks across all pages is {total_blocks}, expected at least 8")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

    # -----------------------------------------------------------------------------
    # reorganize-meeting-notes-structure
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_reorganize_meeting_notes_structure(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Task: Reorganize meeting notes by creating backup and moving pages.
    
    Validates:
    1. "Meeting Notes Archive" page exists as duplicate
    2. Pages containing "Sprint Planning" and "Retrospective" are children of Meeting Notes
    3. Meeting Notes page contains bulleted lists and quote block
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    # 1. Find "Meeting Notes Archive" page
    try:
        archive_results = final_state_backend.query({
            "collection": "pages",
            "filter": {"title": "Meeting Notes Archive"}
        })
    
        if not archive_results:
            errors.append("[X] Page 'Meeting Notes Archive' not found")
        else:
            checks_passed.append("[C] Page 'Meeting Notes Archive' found")
    
        # 2. Find "Meeting Notes" page
        meeting_notes_results = final_state_backend.query({
            "collection": "pages",
            "filter": {"title": "Meeting Notes"}
        })
    
        if not meeting_notes_results:
            errors.append("[X] Page 'Meeting Notes' not found")
        else:
            checks_passed.append("[C] Page 'Meeting Notes' found")
    
        meeting_notes_page = meeting_notes_results[0]
        meeting_notes_id = meeting_notes_page.get("_id")
    
        # 3. Find children of Meeting Notes
        meeting_children = final_state_backend.query({
            "collection": "pages",
            "filter": {"parentId": meeting_notes_id}
        })
    
        # Check for Sprint Planning and Retrospective pages
        child_titles = [child.get("title", "") for child in meeting_children]
        has_sprint_planning = any("Sprint Planning" in title for title in child_titles)
        has_retrospective = any("Retrospective" in title for title in child_titles)
    
        if not has_sprint_planning:
            errors.append("[X] No page containing 'Sprint Planning' found as child of Meeting Notes")
        else:
            checks_passed.append("[C] page containing 'Sprint Planning' found as child of Meeting Notes")
    
        if not has_retrospective:
            errors.append("[X] No page containing 'Retrospective' found as child of Meeting Notes")
        else:
            checks_passed.append("[C] page containing 'Retrospective' found as child of Meeting Notes")
    
        # 4. Check Meeting Notes has bulleted lists and quote block
        content_blocks = final_state_backend.query({
            "collection": "blocks",
            "filter": {"pageId": meeting_notes_page.get("_id")}
        })
        has_bulleted_list = any(block.get("type") == "bulletedList" for block in content_blocks)
        has_quote = any(block.get("type") == "quote" for block in content_blocks)
    
        if not has_bulleted_list:
            errors.append("[X] Meeting Notes page does not have bulleted lists")
        else:
            checks_passed.append("[C] Meeting Notes page has bulleted lists")
    
        if not has_quote:
            errors.append("[X] Meeting Notes page does not have quote block with guidelines")
        else:
            checks_passed.append("[C] Meeting Notes page has quote block with guidelines")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

    # -----------------------------------------------------------------------------
    # create-meeting-archive-2024
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_create_meeting_archive_2024(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Task: Organize old meeting content into centralized archive.
    
    Validates:
    1. "Meeting Archive 2024" page exists with calendar icon and is marked as favorite
    2. At least 3 meeting pages moved as children under the archive
    3. Archive page contains bulleted list summary section
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    # 1. Find "Meeting Archive 2024" page
    try:
        archive_results = final_state_backend.query({
            "collection": "pages",
            "filter": {"title": "Meeting Archive 2024"}
        })
    
        if not archive_results:
            errors.append("[X] Page 'Meeting Archive 2024' not found")
        else:
            checks_passed.append("[C] Page 'Meeting Archive 2024' found")
    
        archive_page = archive_results[0]
        archive_id = archive_page.get("_id")
    
        # Check calendar icon
        if archive_page.get("icon") != "📅":
            errors.append("[X] Meeting Archive 2024 does not have calendar icon")
        else:
            checks_passed.append("[C] Meeting Archive 2024 has calendar icon")
    
        # Check if marked as favorite
        if not archive_page.get("isFavorite", False):
            errors.append("[X] Meeting Archive 2024 is not marked as favorite")
        else:
            checks_passed.append("[C] Meeting Archive 2024 is marked as favorite")
    
        # 2. Find children of archive
        archive_children = final_state_backend.query({
            "collection": "pages",
            "filter": {"parentId": archive_id}
        })
    
        if len(archive_children) < 3:
            errors.append(f"[X] Meeting Archive 2024 has {len(archive_children)} children, expected at least 3 meeting pages")
        else:
            checks_passed.append(f"[C] Meeting Archive 2024 has {len(archive_children)} children, expected at least 3 meeting pages")
    
        # 3. Check archive has bulleted list summary
        content_blocks = final_state_backend.query({
            "collection": "blocks",
            "filter": {"pageId": archive_page.get("_id")}
        })
        has_bulleted_list = any(block.get("type") == "bulletedList" for block in content_blocks)
    
        if not has_bulleted_list:
            errors.append("[X] Meeting Archive 2024 does not have bulleted list summary section")
        else:
            checks_passed.append("[C] Meeting Archive 2024 has bulleted list summary section")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

    # -----------------------------------------------------------------------------
    # create-developer-onboarding-hub
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_create_developer_onboarding_hub(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Task: Create developer onboarding hub with duplicated template and sub-pages.
    
    Validates:
    1. "Developer Onboarding Hub" page exists with graduation cap icon and is marked as favorite
    2. Contains 4 child pages total (duplicated template plus 3 new pages)
    3. Each new sub-page contains at least one heading, bulleted list, and todo block
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    # 1. Find "Developer Onboarding Hub" page
    try:
        hub_results = final_state_backend.query({
            "collection": "pages",
            "filter": {"title": "Developer Onboarding Hub"}
        })
    
        if not hub_results:
            errors.append("[X] Page 'Developer Onboarding Hub' not found")
        else:
            checks_passed.append("[C] Page 'Developer Onboarding Hub' found")
    
        hub_page = hub_results[0]
        hub_id = hub_page.get("_id")
    
        # Check graduation cap icon
        if hub_page.get("icon") != "🎓":
            errors.append("[X] Developer Onboarding Hub does not have graduation cap icon")
        else:
            checks_passed.append("[C] Developer Onboarding Hub has graduation cap icon")
    
        # Check if marked as favorite
        if not hub_page.get("isFavorite", False):
            errors.append("[X] Developer Onboarding Hub is not marked as favorite")
        else:
            checks_passed.append("[C] Developer Onboarding Hub is marked as favorite")
    
        # 2. Find children of hub
        hub_children = final_state_backend.query({
            "collection": "pages",
            "filter": {"parentId": hub_id}
        })
    
        if len(hub_children) < 4:
            errors.append(f"[X] Developer Onboarding Hub has {len(hub_children)} children, expected 4 pages")
        else:
            checks_passed.append(f"[C] Developer Onboarding Hub has {len(hub_children)} children, expected 4 pages")
    
        # 3. Check new sub-pages for required content
        expected_pages = ["Setup Checklist", "Code Review Guidelines", "Team Contacts"]
        for expected_title in expected_pages:
            matching_pages = [p for p in hub_children if expected_title in p.get("title", "")]
            if matching_pages:
                page = matching_pages[0]
                content_blocks = final_state_backend.query({
                    "collection": "blocks",
                    "filter": {"pageId": page.get("_id")}
                })
                has_heading = any(block.get("type") in ["heading1", "heading2", "heading3"] for block in content_blocks)
                has_bulleted = any(block.get("type") == "bulletedList" for block in content_blocks)
                has_todo = any(block.get("type") == "todo" for block in content_blocks)
            
                if not (has_heading and has_bulleted and has_todo):
                    errors.append(f"[X] Page '{expected_title}' missing required blocks (heading, bulletedList, todo)")
                else:
                    checks_passed.append(f"[C] Page '{expected_title}' has required blocks (heading, bulletedList, todo)")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

    # -----------------------------------------------------------------------------
    # create-new-hire-checklist-template
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_create_new_hire_checklist_template(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Task: Build onboarding workflow with duplicated guide and HR Resources parent.
    
    Validates:
    1. "New Hire Checklist Template" with person icon exists
    2. "HR Resources" parent with briefcase icon and favorite status exists
    3. Template contains: heading1, bulletedList, >=3 todo blocks, divider, code block
    4. Template is under HR Resources parent
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    # 1. Find "New Hire Checklist Template" page
    try:
        template_results = final_state_backend.query({
            "collection": "pages",
            "filter": {"title": "New Hire Checklist Template"}
        })
    
        if not template_results:
            errors.append("[X] Page 'New Hire Checklist Template' not found")
        else:
            checks_passed.append("[C] Page 'New Hire Checklist Template' found")
    
        template_page = template_results[0]
    
        # Check person icon (could be various person emojis)
        icon = template_page.get("icon", "")
        if icon not in ["👤", "👨", "👩", "🧑", "👱"]:
            errors.append(f"[X] New Hire Checklist Template does not have person icon (has {icon})")
        else:
            checks_passed.append(f"[C] New Hire Checklist Template has person icon (has {icon})")
    
        # 2. Find "HR Resources" parent page
        hr_results = final_state_backend.query({
            "collection": "pages",
            "filter": {"title": "HR Resources"}
        })
    
        if not hr_results:
            errors.append("[X] Page 'HR Resources' not found")
        else:
            checks_passed.append("[C] Page 'HR Resources' found")
    
        hr_page = hr_results[0]
    
        # Check briefcase icon
        if hr_page.get("icon") != "💼":
            errors.append("[X] HR Resources does not have briefcase icon")
        else:
            checks_passed.append("[C] HR Resources has briefcase icon")
    
        # Check if HR Resources is marked as favorite
        if not hr_page.get("isFavorite", False):
            errors.append("[X] HR Resources is not marked as favorite")
        else:
            checks_passed.append("[C] HR Resources is marked as favorite")
    
        # 3. Check template is under HR Resources
        if template_page.get("parentId") != hr_page.get("_id"):
            errors.append("[X] New Hire Checklist Template is not under HR Resources parent")
        else:
            checks_passed.append("[C] New Hire Checklist Template is under HR Resources parent")
    
        # 4. Check template content
        content_blocks = final_state_backend.query({
            "collection": "blocks",
            "filter": {"pageId": template_page.get("_id")}
        })
        block_types = [block.get("type") for block in content_blocks]
    
        has_heading1 = "heading1" in block_types
        has_bulleted = "bulletedList" in block_types
        todo_count = block_types.count("todo")
        has_divider = "divider" in block_types
        has_code = "code" in block_types
    
        if not has_heading1:
            errors.append("[X] Template missing heading1 block")
        else:
            checks_passed.append("[C] Template has heading1 block")
        if not has_bulleted:
            errors.append("[X] Template missing bulletedList block")
        else:
            checks_passed.append("[C] Template has bulletedList block")
        if todo_count < 3:
            errors.append(f"[X] Template has {todo_count} todo blocks, expected at least 3")
        else:
            checks_passed.append(f"[C] Template has {todo_count} todo blocks, expected at least 3")
        if not has_divider:
            errors.append("[X] Template missing divider block")
        else:
            checks_passed.append("[C] Template has divider block")
        if not has_code:
            errors.append("[X] Template missing code block")
        else:
            checks_passed.append("[C] Template has code block")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

    # -----------------------------------------------------------------------------
    # create-knowledge-base-hub
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_create_knowledge_base_hub(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Task: Create documentation center with Engineering Wiki and duplicated API docs.
    
    Validates:
    1. "Knowledge Base" page with books icon and marked as favorite
    2. "Engineering Wiki" moved under Knowledge Base
    3. "Developer Quick Start" (duplicated API Documentation) exists under Knowledge Base
    4. Quick Start has customized content sections
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    # 1. Find "Knowledge Base" page
    try:
        kb_results = final_state_backend.query({
            "collection": "pages",
            "filter": {"title": "Knowledge Base"}
        })
    
        if not kb_results:
            errors.append("[X] Page 'Knowledge Base' not found")
        else:
            checks_passed.append("[C] Page 'Knowledge Base' found")
    
        kb_page = kb_results[0]
        kb_id = kb_page.get("_id")
    
        # Check books icon
        if kb_page.get("icon") != "📚":
            errors.append("[X] Knowledge Base does not have books icon")
        else:
            checks_passed.append("[C] Knowledge Base has books icon")
    
        # Check if marked as favorite
        if not kb_page.get("isFavorite", False):
            errors.append("[X] Knowledge Base is not marked as favorite")
        else:
            checks_passed.append("[C] Knowledge Base is marked as favorite")
    
        # 2. Check "Engineering Wiki" is under Knowledge Base
        eng_wiki_results = final_state_backend.query({
            "collection": "pages",
            "filter": {"title": "Engineering Wiki"}
        })
    
        if not eng_wiki_results:
            errors.append("[X] Engineering Wiki page not found")
        else:
            checks_passed.append("[C] Engineering Wiki page found")
    
        if eng_wiki_results[0].get("parentId") != kb_id:
            errors.append("[X] Engineering Wiki is not moved under Knowledge Base")
        else:
            checks_passed.append("[C] Engineering Wiki is moved under Knowledge Base")
    
        # 3. Find "Developer Quick Start"
        quick_start_results = final_state_backend.query({
            "collection": "pages",
            "filter": {"title": "Developer Quick Start"}
        })
    
        if not quick_start_results:
            errors.append("[X] Developer Quick Start page not found (duplicated API Documentation)")
        else:
            checks_passed.append("[C] Developer Quick Start page found (duplicated API Documentation)")
    
        quick_start_page = quick_start_results[0]
    
        # Check it's under Knowledge Base
        if quick_start_page.get("parentId") != kb_id:
            errors.append("[X] Developer Quick Start is not under Knowledge Base")
        else:
            checks_passed.append("[C] Developer Quick Start is under Knowledge Base")
    
        # 4. Check Quick Start has customized content
        content_blocks = final_state_backend.query({
            "collection": "blocks",
            "filter": {"pageId": quick_start_page.get("_id")}
        })
        if len(content_blocks) == 0:
            errors.append("[X] Developer Quick Start has no customized content sections")
        else:
            checks_passed.append("[C] Developer Quick Start has customized content sections")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

    # -----------------------------------------------------------------------------
    # create-template-library
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_create_template_library(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Task: Create knowledge sharing system by organizing and duplicating templates.
    
    Validates:
    1. "Template Library" page with book icon exists
    2. Contains heading, callout, numbered list, and code block
    3. Has duplicated template pages as children
    4. Original template pages are archived
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    # 1. Find "Template Library" page
    try:
        library_results = final_state_backend.query({
            "collection": "pages",
            "filter": {"title": "Template Library"}
        })
    
        if not library_results:
            errors.append("[X] Page 'Template Library' not found")
        else:
            checks_passed.append("[C] Page 'Template Library' found")
    
        library_page = library_results[0]
        library_id = library_page.get("_id")
    
        # Check book icon
        if library_page.get("icon") not in ["📕", "📖", "📚", "📙"]:
            errors.append("[X] Template Library does not have book icon")
        else:
            checks_passed.append("[C] Template Library has book icon")
    
        # 2. Check content structure
        content_blocks = final_state_backend.query({
            "collection": "blocks",
            "filter": {"pageId": library_page.get("_id")}
        })
        block_types = [block.get("type") for block in content_blocks]
    
        has_heading = any(t in ["heading1", "heading2", "heading3"] for t in block_types)
        has_callout = "callout" in block_types
        has_numbered = "numberedList" in block_types
        has_code = "code" in block_types
    
        if not has_heading:
            errors.append("[X] Template Library missing heading block")
        else:
            checks_passed.append("[C] Template Library has heading block")
        if not has_callout:
            errors.append("[X] Template Library missing callout block")
        else:
            checks_passed.append("[C] Template Library has callout block")
        if not has_numbered:
            errors.append("[X] Template Library missing numbered list")
        else:
            checks_passed.append("[C] Template Library has numbered list")
        if not has_code:
            errors.append("[X] Template Library missing code block")
        else:
            checks_passed.append("[C] Template Library has code block")
    
        # 3. Check for duplicated template pages as children
        library_children = final_state_backend.query({
            "collection": "pages",
            "filter": {"parentId": library_id}
        })
    
        if len(library_children) == 0:
            errors.append("[X] Template Library has no duplicated template pages as children")
        else:
            checks_passed.append("[C] Template Library has duplicated template pages as children")
    
        # 4. Check if original template pages are archived
        # Query only archived pages instead of all pages for efficiency
        archived_pages = final_state_backend.query({
            "collection": "pages",
            "filter": {"isArchived": True}
        })
    
        # Check if any archived pages are templates (not the library itself or its children)
        template_keywords = ["template", "standup", "kickoff", "checklist"]
        archived_template_count = sum(
            1 for page in archived_pages
            if any(keyword in page.get("title", "").lower() for keyword in template_keywords)
            and page.get("_id") != library_id
            and page.get("parentId") != library_id
        )
    
        # Verify that templates exist in library and originals were archived
        if len(library_children) == 0:
            errors.append("[X] Template Library has no template pages as children")
        else:
            checks_passed.append("[C] Template Library has template pages as children")
    
        # If there are no archived templates but we have duplicates in library,
        # it might mean originals weren't archived (or didn't exist initially)
        # We'll be lenient but note this in the success message
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

    # -----------------------------------------------------------------------------
    # consolidate-meeting-notes
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_consolidate_meeting_notes(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Task: Consolidate scattered meeting notes with archive subpages.
    
    Validates:
    1. "Meeting Notes" page exists
    2. Two new subpages: "Sprint Reviews Archive" (folder icon) and "Team Meetings Archive" (calendar icon)
    3. "Team Retrospective" page moved under Team Meetings Archive
    4. Main page has divider, heading1 "Archive Organization", and numberedList
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    # 1. Find "Meeting Notes" page
    try:
        meeting_notes_results = final_state_backend.query({
            "collection": "pages",
            "filter": {"title": "Meeting Notes"}
        })
    
        if not meeting_notes_results:
            errors.append("[X] Page 'Meeting Notes' not found")
        else:
            checks_passed.append("[C] Page 'Meeting Notes' found")
    
        meeting_notes_page = meeting_notes_results[0]
        meeting_notes_id = meeting_notes_page.get("_id")
    
        # 2. Find "Sprint Reviews Archive" with folder icon
        sprint_archive_results = final_state_backend.query({
            "collection": "pages",
            "filter": {"title": "Sprint Reviews Archive", "parentId": meeting_notes_id}
        })
    
        if not sprint_archive_results:
            errors.append("[X] Page 'Sprint Reviews Archive' not found as child of Meeting Notes")
        else:
            checks_passed.append("[C] Page 'Sprint Reviews Archive' found as child of Meeting Notes")
    
        sprint_archive = sprint_archive_results[0]
        if sprint_archive.get("icon") != "📁":
            errors.append("[X] Sprint Reviews Archive does not have folder icon")
        else:
            checks_passed.append("[C] Sprint Reviews Archive has folder icon")
    
        # 3. Find "Team Meetings Archive" with calendar icon
        team_archive_results = final_state_backend.query({
            "collection": "pages",
            "filter": {"title": "Team Meetings Archive", "parentId": meeting_notes_id}
        })
    
        if not team_archive_results:
            errors.append("[X] Page 'Team Meetings Archive' not found as child of Meeting Notes")
        else:
            checks_passed.append("[C] Page 'Team Meetings Archive' found as child of Meeting Notes")
    
        team_archive = team_archive_results[0]
        team_archive_id = team_archive.get("_id")
        if team_archive.get("icon") != "📅":
            errors.append("[X] Team Meetings Archive does not have calendar icon")
        else:
            checks_passed.append("[C] Team Meetings Archive has calendar icon")
    
        # 4. Check "Team Retrospective" moved under Team Meetings Archive
        retrospective_results = final_state_backend.query({
            "collection": "pages",
            "filter": {"title": "Team Retrospective"}
        })
    
        if retrospective_results:
            if retrospective_results[0].get("parentId") != team_archive_id:
                errors.append("[X] Team Retrospective is not moved under Team Meetings Archive")
            else:
                checks_passed.append("[C] Team Retrospective is moved under Team Meetings Archive")
    
        # 5. Check main page content
        content_blocks = final_state_backend.query({
            "collection": "blocks",
            "filter": {"pageId": meeting_notes_page.get("_id")}
        })
        has_divider = any(block.get("type") == "divider" for block in content_blocks)
        has_archive_heading = any(
            block.get("type") == "heading1" and "Archive Organization" in block.get("content", "")
            for block in content_blocks
        )
        has_numbered_list = any(block.get("type") == "numberedList" for block in content_blocks)
    
        if not has_divider:
            errors.append("[X] Meeting Notes page missing divider")
        else:
            checks_passed.append("[C] Meeting Notes page has divider")
        if not has_archive_heading:
            errors.append("[X] Meeting Notes page missing heading1 'Archive Organization'")
        else:
            checks_passed.append("[C] Meeting Notes page has heading1 'Archive Organization'")
        if not has_numbered_list:
            errors.append("[X] Meeting Notes page missing numbered list explaining archive structure")
        else:
            checks_passed.append("[C] Meeting Notes page has numbered list explaining archive structure")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

    # -----------------------------------------------------------------------------
    # create-project-management-hub
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_create_project_management_hub(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Task: Create comprehensive project workspace with sub-pages and cover image.
    
    Validates:
    1. "Project Management Hub" with target icon, cover image, and favorite status
    2. Has 4 sub-pages
    3. Existing project pages moved under "Active Projects"
    4. Each section contains numbered lists, todo items, headings, and dividers
    5. Hub page has structured organizational content
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    # 1. Find "Project Management Hub" page
    try:
        hub_results = final_state_backend.query({
            "collection": "pages",
            "filter": {"title": "Project Management Hub"}
        })
    
        if not hub_results:
            errors.append("[X] Page 'Project Management Hub' not found")
        else:
            checks_passed.append("[C] Page 'Project Management Hub' found")
    
        hub_page = hub_results[0]
        hub_id = hub_page.get("_id")
    
        # Check target icon
        if hub_page.get("icon") != "🎯":
            errors.append("[X] Project Management Hub does not have target icon")
        else:
            checks_passed.append("[C] Project Management Hub has target icon")
    
        # Check cover image
        cover_url = hub_page.get("coverImage") or hub_page.get("coverUrl") or hub_page.get("cover")
        if not cover_url:
            errors.append("[X] Project Management Hub does not have cover image")
        else:
            checks_passed.append("[C] Project Management Hub has cover image")
    
        # Check if marked as favorite
        if not hub_page.get("isFavorite", False):
            errors.append("[X] Project Management Hub is not marked as favorite")
        else:
            checks_passed.append("[C] Project Management Hub is marked as favorite")
    
        # 2. Find children of hub
        hub_children = final_state_backend.query({
            "collection": "pages",
            "filter": {"parentId": hub_id}
        })
    
        if len(hub_children) < 4:
            errors.append(f"[X] Project Management Hub has {len(hub_children)} sub-pages, expected 4")
        else:
            checks_passed.append(f"[C] Project Management Hub has {len(hub_children)} sub-pages, expected 4")
    
        # 3. Check for "Active Projects" page and verify it has project children
        active_projects_results = final_state_backend.query({
            "collection": "pages",
            "filter": {"title": "Active Projects", "parentId": hub_id}
        })
    
        if not active_projects_results:
            errors.append("[X] Active Projects sub-page not found under hub")
        else:
            checks_passed.append("[C] Active Projects sub-page found under hub")
    
        active_projects_id = active_projects_results[0].get("_id")
    
        # Check if Active Projects has children (moved project pages)
        active_projects_children = final_state_backend.query({
            "collection": "pages",
            "filter": {"parentId": active_projects_id}
        })
    
        if len(active_projects_children) == 0:
            errors.append("[X] No existing project pages moved under Active Projects")
        else:
            checks_passed.append("[C] existing project pages moved under Active Projects")
    
        moved_count = len(active_projects_children)
    
        # 4. Check hub has structured content
        content_blocks = final_state_backend.query({
            "collection": "blocks",
            "filter": {"pageId": hub_page.get("_id")}
        })
        has_numbered = any(block.get("type") == "numberedList" for block in content_blocks)
        has_heading = any(block.get("type") in ["heading1", "heading2", "heading3"] for block in content_blocks)
        has_divider = any(block.get("type") == "divider" for block in content_blocks)
    
        if not (has_numbered and has_heading and has_divider):
            errors.append("[X] Hub page missing required structured content (numbered lists, headings, dividers)")
        else:
            checks_passed.append("[C] Hub page has required structured content (numbered lists, headings, dividers)")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_agent_reorganize_project_documentation_by_activity(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Task: Reorganize project documentation by identifying most active pages and filtering by callout blocks.
    
    Validates:
    1. "Active Projects" exists with 🔥 icon as sibling of "Project Documentation"
    2. Page with most sub-pages moved under Active Projects
    3. Numbered list contains only pages with callout blocks
    4. Hierarchy preserved for moved pages
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    # 1. Find "Project Documentation" page
    try:
        proj_doc_results = final_state_backend.query({
            "collection": "pages",
            "filter": {"title": "Project Documentation"}
        })
    
        if not proj_doc_results:
            errors.append("[X] Page 'Project Documentation' not found")
        else:
            checks_passed.append("[C] Page 'Project Documentation' found")
    
        proj_doc_page = proj_doc_results[0]
        proj_doc_id = proj_doc_page.get("_id")
        proj_doc_parent = proj_doc_page.get("parentId")
    
        # 2. Find "Active Projects" page
        active_proj_results = final_state_backend.query({
            "collection": "pages",
            "filter": {"title": "Active Projects"}
        })
    
        if not active_proj_results:
            errors.append("[X] Page 'Active Projects' not found")
        else:
            checks_passed.append("[C] Page 'Active Projects' found")
    
        active_proj_page = active_proj_results[0]
        active_proj_id = active_proj_page.get("_id")
    
        # Check icon
        if active_proj_page.get("icon") != "🔥":
            errors.append("[X] Active Projects does not have 🔥 icon")
        else:
            checks_passed.append("[C] Active Projects has 🔥 icon")
    
        # Check if Active Projects is a sibling of Project Documentation (same parent)
        if active_proj_page.get("parentId") != proj_doc_parent:
            errors.append("[X] Active Projects is not a sibling of Project Documentation")
        else:
            checks_passed.append("[C] Active Projects is a sibling of Project Documentation")
    
        # 3. Find children of Active Projects (should have the moved page)
        active_children = final_state_backend.query({
            "collection": "pages",
            "filter": {"parentId": active_proj_id}
        })
    
        if len(active_children) == 0:
            errors.append("[X] No page moved under Active Projects")
        else:
            checks_passed.append("[C] page moved under Active Projects")
    
        # Get the moved page (should be the one with most sub-pages)
        moved_page = active_children[0]
        moved_page_id = moved_page.get("_id")
    
        # Check that moved page has sub-pages (hierarchy preserved)
        moved_page_children = final_state_backend.query({
            "collection": "pages",
            "filter": {"parentId": moved_page_id}
        })
    
        if len(moved_page_children) == 0:
            errors.append("[X] Moved page has no sub-pages (hierarchy not preserved)")
        else:
            checks_passed.append("[C] Moved page has sub-pages (hierarchy preserved)")
    
        # 4. Get remaining children of Project Documentation
        proj_doc_children = final_state_backend.query({
            "collection": "pages",
            "filter": {"parentId": proj_doc_id}
        })
    
        # For each remaining child, check if it has callout blocks
        pages_with_callouts = []
        for child in proj_doc_children:
            child_blocks = final_state_backend.query({
                "collection": "blocks",
                "filter": {"pageId": child.get("_id")}
            })
            has_callout = any(block.get("type") == "callout" for block in child_blocks)
            if has_callout:
                pages_with_callouts.append(child.get("title"))
    
        # Check numbered list in Active Projects content
        active_blocks = final_state_backend.query({
            "collection": "blocks",
            "filter": {"pageId": active_proj_page.get("_id")}
        })
        numbered_lists = [block for block in active_blocks if block.get("type") == "numberedList"]
        numbered_list_count = len(numbered_lists)
        pages_with_callouts_count = len(pages_with_callouts)
    
        # If there are pages with callouts, numbered list should exist and match
        if pages_with_callouts_count > 0:
            if numbered_list_count == 0:
                errors.append(f"[X] Active Projects missing numbered list for {pages_with_callouts_count} pages with callouts")
            else:
                checks_passed.append(f"[C] Active Projects has numbered list for {pages_with_callouts_count} pages with callouts")
            if numbered_list_count < pages_with_callouts_count:
                errors.append(f"[X] Numbered list has {numbered_list_count} items but {pages_with_callouts_count} pages have callouts")
            else:
                checks_passed.append(f"[C] Numbered list has {numbered_list_count} items but {pages_with_callouts_count} pages have callouts")
    
        # If no pages have callouts, numbered list should be empty or non-existent (both are acceptable)
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

    # -----------------------------------------------------------------------------
    # create-guideline-categories-summary
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_create_guideline_categories_summary(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Task: Analyze callout blocks and create summary section on Project Guidelines page.
    
    Validates:
    1. Guideline Categories Summary heading_2 exists after main heading
    2. Numbered list with 6 items showing counts by background color
    3. Counts are correct (5 each for yellow, orange, red, green, blue, gray)
    4. Divider and total paragraph with bold formatting
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    # 1. Find "Project Guidelines & Best Practices" page
    try:
        guidelines_results = final_state_backend.query({
            "collection": "pages",
            "filter": {"title": "Project Guidelines & Best Practices"}
        })
    
        if not guidelines_results:
            errors.append("[X] Page 'Project Guidelines & Best Practices' not found")
        else:
            checks_passed.append("[C] Page 'Project Guidelines & Best Practices' found")
    
        guidelines_page = guidelines_results[0]
        content_blocks = final_state_backend.query({
            "collection": "blocks",
            "filter": {"pageId": guidelines_page.get("_id")}
        })
    
        # 2. Count callouts by background color
        callout_counts = {
            "yellow": 0,
            "orange": 0,
            "red": 0,
            "green": 0,
            "blue": 0,
            "gray": 0
        }
    
        for block in content_blocks:
            if block.get("type") == "callout":
                bg = block.get("properties", {}).get("backgroundColor", "").lower()
                for color in callout_counts.keys():
                    if color in bg:
                        callout_counts[color] += 1
                        break
    
        total_callouts = sum(callout_counts.values())
    
        # 3. Find Guideline Categories Summary heading
        summary_heading_found = False
        summary_heading_idx = -1
        for idx, block in enumerate(content_blocks):
            if block.get("type") == "heading2":
                text = str(block.get("text", "") or block.get("content", ""))
                if "Guideline Categories Summary" in text:
                    summary_heading_found = True
                    summary_heading_idx = idx
                    break
    
        if not summary_heading_found:
            errors.append("[X] Guideline Categories Summary heading_2 not found")
        else:
            checks_passed.append("[C] Guideline Categories Summary heading_2 found")
    
        # 4. Check for numbered list after heading
        numbered_list_items = []
        for i in range(summary_heading_idx + 1, min(summary_heading_idx + 10, len(content_blocks))):
            if content_blocks[i].get("type") == "numberedList":
                numbered_list_items.append(content_blocks[i])
    
        if len(numbered_list_items) < 6:
            errors.append(f"[X] Expected 6 numbered list items for categories, found {len(numbered_list_items)}")
        else:
            checks_passed.append(f"[C] Found 6 numbered list items for categories as expected")
    
        # 5. Validate numbered list content
        expected_categories = [
            {"emoji": "💡", "text": "Tips & Suggestions", "color": "yellow"},
            {"emoji": "⚠️", "text": "Warnings", "color": "orange"},
            {"emoji": "🚨", "text": "Critical Rules", "color": "red"},
            {"emoji": "✅", "text": "Best Practices", "color": "green"},
            {"emoji": "📝", "text": "Notes", "color": "blue"},
            {"emoji": "🔒", "text": "Security", "color": "gray"}
        ]
    
        for idx, expected in enumerate(expected_categories):
            if idx >= len(numbered_list_items):
                errors.append(f"[X] Missing category {idx + 1}")
            else:
                checks_passed.append(f"[C] has category {idx + 1}")
        
            item = numbered_list_items[idx]
            text = str(item.get("text", "") or item.get("content", ""))
        
            if expected["emoji"] not in text:
                errors.append(f"[X] Category {idx + 1} missing emoji {expected['emoji']}")
            else:
                checks_passed.append(f"[C] Category {idx + 1} has emoji {expected['emoji']}")
        
            if expected["text"] not in text:
                errors.append(f"[X] Category {idx + 1} missing text '{expected['text']}'")
            else:
                checks_passed.append(f"[C] Category {idx + 1} has text '{expected['text']}'")
        
            if expected["color"] not in text.lower():
                errors.append(f"[X] Category {idx + 1} missing color reference '{expected['color']}'")
            else:
                checks_passed.append(f"[C] Category {idx + 1} has color reference '{expected['color']}'")
    
        # 6. Check for divider after numbered list
        has_divider = False
        divider_idx = -1
        for i in range(summary_heading_idx + 7, len(content_blocks)):
            if content_blocks[i].get("type") == "divider":
                has_divider = True
                divider_idx = i
                break
    
        if not has_divider:
            errors.append("[X] Missing divider after numbered list")
        else:
            checks_passed.append("[C] has divider after numbered list")
    
        # 7. Check for total paragraph with bold formatting
        has_total_paragraph = False
        for i in range(divider_idx + 1, min(divider_idx + 3, len(content_blocks))):
            if content_blocks[i].get("type") == "paragraph":
                text = str(content_blocks[i].get("text", "") or content_blocks[i].get("content", ""))
                if "Total Guidelines" in text and str(total_callouts) in text:
                    has_total_paragraph = True
                    break
    
        if not has_total_paragraph:
            errors.append("[X] Missing paragraph with 'Total Guidelines' count")
        else:
            checks_passed.append("[C] has paragraph with 'Total Guidelines' count")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

    # -----------------------------------------------------------------------------
    # add-weekly-standup-progress-section-v2
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_add_weekly_standup_progress_section(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Task: Add In Progress section with todos and template update timestamp to Weekly Standup Template page.
    
    Validates:
    1. '🔄 In Progress This Week' heading_2 exists after 'What I plan to do next week' but before 'Blockers'
    2. Three unchecked todos with exact text and emojis specified
    3. Divider block follows the todos
    4. Italic paragraph with today's date appears at the end
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    # Find Weekly Standup Template page
    try:
        template_results = final_state_backend.query({
            "collection": "pages",
            "filter": {"title": "Weekly Standup Template"}
        })
    
        if not template_results:
            errors.append("[X] Page 'Weekly Standup Template' not found")
        else:
            checks_passed.append("[C] Page 'Weekly Standup Template' found")
    
        template_page = template_results[0]
        page_id = template_page.get("_id")
    
        # Get all blocks for the page
        all_blocks = final_state_backend.query({
            "collection": "blocks",
            "filter": {"pageId": page_id}
        })
    
        # Sort blocks by order
        all_blocks.sort(key=lambda b: b.get("order", 0))
    
        # Find the new heading '🔄 In Progress This Week'
        progress_heading_idx = -1
        for idx, block in enumerate(all_blocks):
            if block.get("type") == "heading2":
                content = str(block.get("content", ""))
                if "🔄" in content and "In Progress This Week" in content:
                    progress_heading_idx = idx
                    break
    
        if progress_heading_idx == -1:
            errors.append("[X] '🔄 In Progress This Week' heading_2 not found")
        else:
            checks_passed.append("[C] '🔄 In Progress This Week' heading_2 found")
    
        # Verify three unchecked todos after the heading
        expected_todos = [
            "⚡ Optimize database queries for better performance",
            "🛡️ Implement security audit recommendations",
            "📊 Create dashboard for metrics tracking"
        ]
    
        found_todos = []
        for i in range(progress_heading_idx + 1, min(progress_heading_idx + 5, len(all_blocks))):
            if all_blocks[i].get("type") == "todo":
                found_todos.append(all_blocks[i])
    
        if len(found_todos) < 3:
            errors.append(f"[X] Expected 3 todos after heading, found {len(found_todos)}")
        else:
            checks_passed.append(f"[C] Found 3 todos after heading as expected")
    
        for idx, expected_text in enumerate(expected_todos):
            if idx >= len(found_todos):
                errors.append(f"[X] Missing todo: {expected_text}")
            else:
                checks_passed.append(f"[C] has todo: {expected_text}")
        
            todo_content = str(found_todos[idx].get("content", ""))
            if expected_text not in todo_content:
                errors.append(f"[X] Todo text mismatch. Expected: '{expected_text}'")
            else:
                checks_passed.append(f"[C] Todo text mismatch. Expected: '{expected_text}'")
        
            # Check that todo is unchecked
            if found_todos[idx].get("properties", {}).get("checked", False):
                errors.append(f"[X] Todo should be unchecked: {expected_text}")
            else:
                checks_passed.append(f"[C] Todo should be unchecked: {expected_text}")
    
        # Check for divider after todos
        has_divider = False
        for i in range(progress_heading_idx + 4, min(progress_heading_idx + 6, len(all_blocks))):
            if all_blocks[i].get("type") == "divider":
                has_divider = True
                break
    
        if not has_divider:
            errors.append("[X] Missing divider after todos")
        else:
            checks_passed.append("[C] has divider after todos")
    
        # Check for italic paragraph at the end with date
        last_blocks = all_blocks[-3:]
        has_timestamp = False
        for block in last_blocks:
            if block.get("type") == "paragraph":
                content = str(block.get("content", ""))
                if "Template last updated:" in content:
                    has_timestamp = True
                    break
    
        if not has_timestamp:
            errors.append("[X] Missing italic paragraph with 'Template last updated:' at end of page")
        else:
            checks_passed.append("[C] has italic paragraph with 'Template last updated:' at end of page")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

    # -----------------------------------------------------------------------------
    # reorganize-external-resources-sections-v2
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_reorganize_external_resources_sections(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Task: Swap Documentation and Tools sections, add Development Resources section on External Resources page.
    
    Validates:
    1. Tools section appears before Documentation section
    2. New '🚀 Development Resources' heading exists after swapped sections
    3. Gray callout with 💻 icon and exact text
    4. Final paragraph shows correct count of bookmark blocks with italic formatting
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    # Find External Resources & Links page
    try:
        page_results = final_state_backend.query({
            "collection": "pages",
            "filter": {"title": "External Resources & Links"}
        })
    
        if not page_results:
            errors.append("[X] Page 'External Resources & Links' not found")
        else:
            checks_passed.append("[C] Page 'External Resources & Links' found")
    
        page_id = page_results[0].get("_id")
    
        # Get all blocks
        all_blocks = final_state_backend.query({
            "collection": "blocks",
            "filter": {"pageId": page_id}
        })
    
        all_blocks.sort(key=lambda b: b.get("order", 0))
    
        # Find Tools and Documentation headings
        tools_idx = -1
        doc_idx = -1
        dev_resources_idx = -1
    
        for idx, block in enumerate(all_blocks):
            content = str(block.get("content", ""))
            if block.get("type") in ["heading2", "heading3"]:
                if "Tools" in content:
                    tools_idx = idx
                elif "Documentation" in content:
                    doc_idx = idx
                elif "🚀" in content and "Development Resources" in content:
                    dev_resources_idx = idx
    
        # Verify Tools comes before Documentation
        if tools_idx == -1:
            errors.append("[X] Tools section heading not found")
        else:
            checks_passed.append("[C] Tools section heading found")
    
        if doc_idx == -1:
            errors.append("[X] Documentation section heading not found")
        else:
            checks_passed.append("[C] Documentation section heading found")
    
        if tools_idx >= doc_idx:
            errors.append("[X] Tools section should appear before Documentation section")
        else:
            checks_passed.append("[C] Tools section should appear before Documentation section")
    
        # Verify Development Resources heading exists
        if dev_resources_idx == -1:
            errors.append("[X] '🚀 Development Resources' heading not found")
        else:
            checks_passed.append("[C] '🚀 Development Resources' heading found")
    
        # Find gray callout with 💻 icon
        has_callout = False
        for i in range(dev_resources_idx + 1, min(dev_resources_idx + 3, len(all_blocks))):
            if all_blocks[i].get("type") == "callout":
                props = all_blocks[i].get("properties", {})
                content = str(all_blocks[i].get("content", ""))
                if props.get("backgroundColor") in ["gray", "gray_background"] and "💻" in props.get("icon", ""):
                    if "Important: All external links should be verified monthly for availability" in content:
                        has_callout = True
                        break
    
        if not has_callout:
            errors.append("[X] Gray callout with 💻 icon and correct text not found")
        else:
            checks_passed.append("[C] Gray callout with 💻 icon and correct text found")
    
        # Count bookmark blocks
        bookmark_count = sum(1 for block in all_blocks if block.get("type") == "bookmark")
    
        # Check for final paragraph with bookmark count
        has_count_paragraph = False
        last_blocks = all_blocks[-3:]
        for block in last_blocks:
            if block.get("type") == "paragraph":
                content = str(block.get("content", ""))
                if "Total external resources:" in content and str(bookmark_count) in content and "links" in content:
                    has_count_paragraph = True
                    break
    
        if not has_count_paragraph:
            errors.append(f"[X] Missing final paragraph with bookmark count ({bookmark_count} links)")
        else:
            checks_passed.append(f"[C] has final paragraph with bookmark count ({bookmark_count} links)")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

    # -----------------------------------------------------------------------------
    # add-engineering-wiki-best-practices-v2
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_add_engineering_wiki_best_practices(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Task: Add comprehensive Development Best Practices section to Engineering Wiki.
    
    Validates:
    1. Divider appears after 'Environment Variables' heading_3
    2. '🔧 Development Best Practices' heading_2 follows divider
    3. Gray callout with checklist icon and bold text
    4. First todo list has 5 items with exact text and emojis
    5. Second heading_3 and todo list with 4 items
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    # Find Engineering Wiki page
    try:
        page_results = final_state_backend.query({
            "collection": "pages",
            "filter": {"title": "Engineering Wiki"}
        })
    
        if not page_results:
            errors.append("[X] Page 'Engineering Wiki' not found")
        else:
            checks_passed.append("[C] Page 'Engineering Wiki' found")
    
        page_id = page_results[0].get("_id")
    
        # Get all blocks
        all_blocks = final_state_backend.query({
            "collection": "blocks",
            "filter": {"pageId": page_id}
        })
    
        all_blocks.sort(key=lambda b: b.get("order", 0))
    
        # Find Environment Variables heading
        env_var_idx = -1
        best_practices_idx = -1
        deployment_idx = -1
    
        for idx, block in enumerate(all_blocks):
            content = str(block.get("content", ""))
            block_type = block.get("type")
        
            if block_type == "heading3" and "Environment Variables" in content:
                env_var_idx = idx
            elif block_type == "heading2" and "🔧" in content and "Development Best Practices" in content:
                best_practices_idx = idx
            elif block_type == "heading3" and "🚀" in content and "Deployment Checklist" in content:
                deployment_idx = idx
    
        if env_var_idx == -1:
            errors.append("[X] 'Environment Variables' heading_3 not found")
        else:
            checks_passed.append("[C] 'Environment Variables' heading_3 found")
    
        # Check for divider after Environment Variables
        has_divider = False
        for i in range(env_var_idx + 1, min(env_var_idx + 3, len(all_blocks))):
            if all_blocks[i].get("type") == "divider":
                has_divider = True
                break
    
        if not has_divider:
            errors.append("[X] Missing divider after 'Environment Variables' heading")
        else:
            checks_passed.append("[C] has divider after 'Environment Variables' heading")
    
        # Check for Best Practices heading
        if best_practices_idx == -1:
            errors.append("[X] '🔧 Development Best Practices' heading_2 not found")
        else:
            checks_passed.append("[C] '🔧 Development Best Practices' heading_2 found")
    
        # Find gray callout with Code Review Checklist
        has_callout = False
        for i in range(best_practices_idx + 1, min(best_practices_idx + 3, len(all_blocks))):
            if all_blocks[i].get("type") == "callout":
                props = all_blocks[i].get("properties", {})
                content = str(all_blocks[i].get("content", ""))
                if props.get("backgroundColor") in ["gray", "gray_background"] and "📋" in props.get("icon", ""):
                    if "Code Review Checklist" in content:
                        has_callout = True
                        break
    
        if not has_callout:
            errors.append("[X] Gray callout with 📋 icon and 'Code Review Checklist' not found")
        else:
            checks_passed.append("[C] Gray callout with 📋 icon and 'Code Review Checklist' found")
    
        # Check for 5 todos for code review
        code_review_todos = [
            "✅ All tests pass locally",
            "📝 Code follows team style guide",
            "🔍 No console.log statements in production code",
            "📊 Performance impact assessed",
            "🔒 Security implications reviewed"
        ]
    
        found_code_todos = 0
        for i in range(best_practices_idx + 2, min(best_practices_idx + 10, len(all_blocks))):
            if all_blocks[i].get("type") == "todo":
                content = str(all_blocks[i].get("content", ""))
                if any(expected in content for expected in code_review_todos):
                    found_code_todos += 1
    
        if found_code_todos < 5:
            errors.append(f"[X] Expected 5 code review todos, found {found_code_todos}")
        else:
            checks_passed.append(f"[C] Found 5 code review todos as expected")
    
        # Check for Deployment Checklist heading
        if deployment_idx == -1:
            errors.append("[X] '🚀 Deployment Checklist' heading_3 not found")
        else:
            checks_passed.append("[C] '🚀 Deployment Checklist' heading_3 found")
    
        # Check for 4 deployment todos
        deployment_todos = [
            "📦 Dependencies updated",
            "🏷️ Version tag created",
            "📄 Changelog updated",
            "✅ Staging environment tested"
        ]
    
        found_deploy_todos = 0
        for i in range(deployment_idx + 1, min(deployment_idx + 6, len(all_blocks))):
            if all_blocks[i].get("type") == "todo":
                content = str(all_blocks[i].get("content", ""))
                if any(expected in content for expected in deployment_todos):
                    found_deploy_todos += 1
    
        if found_deploy_todos < 4:
            errors.append(f"[X] Expected 4 deployment todos, found {found_deploy_todos}")
        else:
            checks_passed.append(f"[C] Found 4 deployment todos as expected")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

    # -----------------------------------------------------------------------------
    # add-handbook-professional-development-v2
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_add_handbook_professional_development(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Task: Add Professional Development section to Company Handbook.
    
    Validates:
    1. New section appears after Benefits section
    2. Heading_2 has '🌟' emoji and exact text
    3. Callout has green background with '💡' icon
    4. All four numbered list items exist with exact text
    5. Quote block contains exact message
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    # Find Company Handbook page
    try:
        page_results = final_state_backend.query({
            "collection": "pages",
            "filter": {"title": "Company Handbook"}
        })
    
        if not page_results:
            errors.append("[X] Page 'Company Handbook' not found")
        else:
            checks_passed.append("[C] Page 'Company Handbook' found")
    
        page_id = page_results[0].get("_id")
    
        # Get all blocks
        all_blocks = final_state_backend.query({
            "collection": "blocks",
            "filter": {"pageId": page_id}
        })
    
        all_blocks.sort(key=lambda b: b.get("order", 0))
    
        # Find Professional Development heading
        prof_dev_idx = -1
        for idx, block in enumerate(all_blocks):
            if block.get("type") == "heading2":
                content = str(block.get("content", ""))
                if "🌟" in content and "Professional Development" in content:
                    prof_dev_idx = idx
                    break
    
        if prof_dev_idx == -1:
            errors.append("[X] '🌟 Professional Development' heading_2 not found")
        else:
            checks_passed.append("[C] '🌟 Professional Development' heading_2 found")
    
        # Check for intro paragraph
        has_intro = False
        for i in range(prof_dev_idx + 1, min(prof_dev_idx + 3, len(all_blocks))):
            if all_blocks[i].get("type") == "paragraph":
                content = str(all_blocks[i].get("content", ""))
                if "We invest in our team's growth through:" in content:
                    has_intro = True
                    break
    
        if not has_intro:
            errors.append("[X] Missing intro paragraph 'We invest in our team's growth through:'")
        else:
            checks_passed.append("[C] has intro paragraph 'We invest in our team's growth through:'")
    
        # Find green callout
        has_callout = False
        for i in range(prof_dev_idx + 2, min(prof_dev_idx + 5, len(all_blocks))):
            if all_blocks[i].get("type") == "callout":
                props = all_blocks[i].get("properties", {})
                content = str(all_blocks[i].get("content", ""))
                if props.get("backgroundColor") in ["green", "green_background"] and "💡" in props.get("icon", ""):
                    if "New initiatives launching Q2 2024" in content:
                        has_callout = True
                        break
    
        if not has_callout:
            errors.append("[X] Green callout with 💡 icon and 'New initiatives launching Q2 2024' not found")
        else:
            checks_passed.append("[C] Green callout with 💡 icon and 'New initiatives launching Q2 2024' found")
    
        # Check for 4 numbered list items
        expected_items = [
            "Monthly learning workshops with industry experts",
            "Annual conference attendance (up to $3,000)",
            "Certification reimbursement program",
            "Internal mentorship matching"
        ]
    
        found_items = 0
        for i in range(prof_dev_idx + 3, min(prof_dev_idx + 10, len(all_blocks))):
            if all_blocks[i].get("type") == "numberedList":
                content = str(all_blocks[i].get("content", ""))
                if any(expected in content for expected in expected_items):
                    found_items += 1
    
        if found_items < 4:
            errors.append(f"[X] Expected 4 numbered list items, found {found_items}")
        else:
            checks_passed.append(f"[C] Found 4 numbered list items as expected")
    
        # Check for quote block
        has_quote = False
        for i in range(prof_dev_idx + 5, min(prof_dev_idx + 12, len(all_blocks))):
            if all_blocks[i].get("type") == "quote":
                content = str(all_blocks[i].get("content", ""))
                if "Learning never stops at our company" in content:
                    has_quote = True
                    break
    
        if not has_quote:
            errors.append("[X] Missing quote block with 'Learning never stops at our company'")
        else:
            checks_passed.append("[C] has quote block with 'Learning never stops at our company'")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

    # -----------------------------------------------------------------------------
    # reorganize-handbook-values-benefits-v2
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_reorganize_handbook_values_benefits(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Task: Complex reorganization of Company Handbook swapping Values and Benefits sections.
    
    Validates:
    1. Benefits section appears where Values section was
    2. Values section is at end
    3. New Culture & Recognition section follows Values
    4. Core Hours subsection inserted between Remote Work and Time Off
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    # Find Company Handbook page
    try:
        page_results = final_state_backend.query({
            "collection": "pages",
            "filter": {"title": "Company Handbook"}
        })
    
        if not page_results:
            errors.append("[X] Page 'Company Handbook' not found")
        else:
            checks_passed.append("[C] Page 'Company Handbook' found")
    
        page_id = page_results[0].get("_id")
    
        # Get all blocks
        all_blocks = final_state_backend.query({
            "collection": "blocks",
            "filter": {"pageId": page_id}
        })
    
        all_blocks.sort(key=lambda b: b.get("order", 0))
    
        # Find key sections
        benefits_idx = -1
        values_idx = -1
        culture_idx = -1
        core_hours_idx = -1
        work_policies_idx = -1
    
        for idx, block in enumerate(all_blocks):
            content = str(block.get("content", ""))
            block_type = block.get("type")
        
            if block_type == "heading2":
                if "Benefits" in content:
                    benefits_idx = idx
                elif "Our Values" in content:
                    values_idx = idx
                elif "🌟" in content and "Culture" in content and "Recognition" in content:
                    culture_idx = idx
                elif "Work Policies" in content:
                    work_policies_idx = idx
            elif block_type == "heading3" and "🕐" in content and "Core Hours" in content:
                core_hours_idx = idx
    
        # Verify sections exist
        if benefits_idx == -1:
            errors.append("[X] Benefits section not found")
        else:
            checks_passed.append("[C] Benefits section found")
    
        if values_idx == -1:
            errors.append("[X] Our Values section not found")
        else:
            checks_passed.append("[C] Our Values section found")
    
        # Check that Benefits comes before Work Policies and Values comes after
        if work_policies_idx != -1:
            if benefits_idx >= work_policies_idx:
                errors.append("[X] Benefits section should appear before Work Policies")
            else:
                checks_passed.append("[C] Benefits section should appear before Work Policies")
            if values_idx <= work_policies_idx:
                errors.append("[X] Our Values section should appear after Work Policies")
            else:
                checks_passed.append("[C] Our Values section should appear after Work Policies")
    
        # Check for Culture & Recognition section
        if culture_idx == -1:
            errors.append("[X] '🌟 Culture & Recognition' heading_2 not found")
        else:
            checks_passed.append("[C] '🌟 Culture & Recognition' heading_2 found")
    
        # Verify Culture comes after Values
        if culture_idx <= values_idx:
            errors.append("[X] Culture & Recognition section should come after Our Values")
        else:
            checks_passed.append("[C] Culture & Recognition section should come after Our Values")
    
        # Check for yellow callout with awards program
        has_callout = False
        for i in range(culture_idx + 1, min(culture_idx + 3, len(all_blocks))):
            if all_blocks[i].get("type") == "callout":
                props = all_blocks[i].get("properties", {})
                content = str(all_blocks[i].get("content", ""))
                if props.get("backgroundColor") in ["yellow", "yellow_background"] and "🏆" in props.get("icon", ""):
                    if "Quarterly awards program" in content:
                        has_callout = True
                        break
    
        if not has_callout:
            errors.append("[X] Yellow callout with 🏆 icon and awards program text not found")
        else:
            checks_passed.append("[C] Yellow callout with 🏆 icon and awards program text found")
    
        # Check for Core Hours subsection
        if core_hours_idx == -1:
            errors.append("[X] '🕐 Core Hours' heading_3 not found")
        else:
            checks_passed.append("[C] '🕐 Core Hours' heading_3 found")
    
        # Check for Core Hours paragraph
        has_core_hours_text = False
        for i in range(core_hours_idx + 1, min(core_hours_idx + 3, len(all_blocks))):
            if all_blocks[i].get("type") == "paragraph":
                content = str(all_blocks[i].get("content", ""))
                if "10 AM - 2 PM" in content and "local timezone" in content:
                    has_core_hours_text = True
                    break
    
        if not has_core_hours_text:
            errors.append("[X] Core Hours paragraph with '10 AM - 2 PM' text not found")
        else:
            checks_passed.append("[C] Core Hours paragraph with '10 AM - 2 PM' text found")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

    # -----------------------------------------------------------------------------
    # add-getting-started-date-section-v2
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_add_getting_started_date_section(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Task: Add date-based section with todos on Getting Started page.
    
    Validates:
    1. Paragraph block with bold text '**2024-02-15**'
    2. Three unchecked todo blocks with exact emoji prefixes and texts
    3. Divider block
    4. Key Features heading at order position 12 or higher
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    # Find Getting Started page
    try:
        page_results = final_state_backend.query({
            "collection": "pages",
            "filter": {"title": "Getting Started"}
        })
    
        if not page_results:
            errors.append("[X] Page 'Getting Started' not found")
        else:
            checks_passed.append("[C] Page 'Getting Started' found")
    
        page_id = page_results[0].get("_id")
    
        # Get all blocks
        all_blocks = final_state_backend.query({
            "collection": "blocks",
            "filter": {"pageId": page_id}
        })
    
        all_blocks.sort(key=lambda b: b.get("order", 0))
    
        # Find date paragraph
        date_paragraph_idx = -1
        for idx, block in enumerate(all_blocks):
            if block.get("type") == "paragraph":
                content = str(block.get("content", ""))
                if "2024-02-15" in content:
                    date_paragraph_idx = idx
                    break
    
        if date_paragraph_idx == -1:
            errors.append("[X] Date paragraph with '**2024-02-15**' not found")
        else:
            checks_passed.append("[C] Date paragraph with '**2024-02-15**' found")
    
        # Check for three todos after date
        expected_todos = [
            "🔍 Master advanced search features",
            "📊 Set up analytics dashboard",
            "🚀 Deploy first production build"
        ]
    
        found_todos = []
        for i in range(date_paragraph_idx + 1, min(date_paragraph_idx + 5, len(all_blocks))):
            if all_blocks[i].get("type") == "todo":
                found_todos.append(all_blocks[i])
    
        if len(found_todos) < 3:
            errors.append(f"[X] Expected 3 todos after date paragraph, found {len(found_todos)}")
        else:
            checks_passed.append(f"[C] Found 3 todos after date paragraph as expected")
    
        for idx, expected_text in enumerate(expected_todos):
            if idx >= len(found_todos):
                errors.append(f"[X] Missing todo: {expected_text}")
            else:
                checks_passed.append(f"[C] has todo: {expected_text}")
        
            todo_content = str(found_todos[idx].get("content", ""))
            if expected_text not in todo_content:
                errors.append(f"[X] Todo text mismatch. Expected: '{expected_text}'")
            else:
                checks_passed.append(f"[C] Todo text mismatch. Expected: '{expected_text}'")
        
            # Check that todo is unchecked
            if found_todos[idx].get("properties", {}).get("checked", False):
                errors.append(f"[X] Todo should be unchecked: {expected_text}")
            else:
                checks_passed.append(f"[C] Todo should be unchecked: {expected_text}")
    
        # Check for divider
        has_divider = False
        for i in range(date_paragraph_idx + 4, min(date_paragraph_idx + 6, len(all_blocks))):
            if all_blocks[i].get("type") == "divider":
                has_divider = True
                break
    
        if not has_divider:
            errors.append("[X] Missing divider after todos")
        else:
            checks_passed.append("[C] has divider after todos")
    
        # Find Key Features heading and check its order
        key_features_order = -1
        for block in all_blocks:
            if block.get("type") == "heading2":
                content = str(block.get("content", ""))
                if "Key Features" in content:
                    key_features_order = block.get("order", 0)
                    break
    
        if key_features_order != -1 and key_features_order < 12:
            errors.append(f"[X] Key Features heading should be at order 12 or higher, found at {key_features_order}")
        else:
            checks_passed.append(f"[C] Key Features heading should be at order 12 or higher, found at {key_features_order}")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

    # -----------------------------------------------------------------------------
    # add-getting-started-progress-tracking-v2
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_add_getting_started_progress_tracking(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Task: Add Progress Tracking section with completion metrics on Getting Started page.
    
    Validates:
    1. Progress Tracking section appears between Quick Start Checklist and Key Features
    2. Callout has Blue background with '📈' icon and bold 'Completion Status:'
    3. Three bulleted list items show correct counts (2 completed, 2 remaining, 50%)
    4. Divider appears after callout
    5. Italic paragraph with note about percentages
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    # Find Getting Started page
    try:
        page_results = final_state_backend.query({
            "collection": "pages",
            "filter": {"title": "Getting Started"}
        })
    
        if not page_results:
            errors.append("[X] Page 'Getting Started' not found")
        else:
            checks_passed.append("[C] Page 'Getting Started' found")
    
        page_id = page_results[0].get("_id")
    
        # Get all blocks
        all_blocks = final_state_backend.query({
            "collection": "blocks",
            "filter": {"pageId": page_id}
        })
    
        all_blocks.sort(key=lambda b: b.get("order", 0))
    
        # Find Progress Tracking heading
        progress_idx = -1
        for idx, block in enumerate(all_blocks):
            if block.get("type") == "heading2":
                content = str(block.get("content", ""))
                if "📊" in content and "Progress Tracking" in content:
                    progress_idx = idx
                    break
    
        if progress_idx == -1:
            errors.append("[X] '📊 Progress Tracking' heading_2 not found")
        else:
            checks_passed.append("[C] '📊 Progress Tracking' heading_2 found")
    
        # Find blue callout with completion status
        has_callout = False
        for i in range(progress_idx + 1, min(progress_idx + 3, len(all_blocks))):
            if all_blocks[i].get("type") == "callout":
                props = all_blocks[i].get("properties", {})
                content = str(all_blocks[i].get("content", ""))
                if props.get("backgroundColor") in ["blue", "blue_background", "Blue"] and "📈" in props.get("icon", ""):
                    if "Completion Status:" in content:
                        has_callout = True
                        break
    
        if not has_callout:
            errors.append("[X] Blue callout with 📈 icon and 'Completion Status:' not found")
        else:
            checks_passed.append("[C] Blue callout with 📈 icon and 'Completion Status:' found")
    
        # Check for three bulleted list items with completion stats
        expected_items = [
            "Tasks Completed: 2 (50%)",
            "Tasks Remaining: 2 (50%)",
            "Last Updated:"
        ]
    
        found_items = 0
        for i in range(progress_idx + 1, min(progress_idx + 10, len(all_blocks))):
            if all_blocks[i].get("type") == "bulletedList":
                content = str(all_blocks[i].get("content", ""))
                if any(expected in content for expected in expected_items):
                    found_items += 1
    
        if found_items < 3:
            errors.append(f"[X] Expected 3 bulleted list items with completion stats, found {found_items}")
        else:
            checks_passed.append(f"[C] Found 3 bulleted list items with completion stats as expected")
    
        # Check for divider
        has_divider = False
        for i in range(progress_idx + 5, min(progress_idx + 15, len(all_blocks))):
            if all_blocks[i].get("type") == "divider":
                has_divider = True
                break
    
        if not has_divider:
            errors.append("[X] Missing divider after callout")
        else:
            checks_passed.append("[C] has divider after callout")
    
        # Check for italic paragraph with note
        has_note = False
        for i in range(progress_idx + 6, min(progress_idx + 16, len(all_blocks))):
            if all_blocks[i].get("type") == "paragraph":
                content = str(all_blocks[i].get("content", ""))
                if "Note:" in content and "percentages" in content and "checklist items" in content:
                    has_note = True
                    break
    
        if not has_note:
            errors.append("[X] Missing italic paragraph with note about percentages")
        else:
            checks_passed.append("[C] has italic paragraph with note about percentages")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

    # -----------------------------------------------------------------------------
    # consolidate-project-guidelines-callouts-v2
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_consolidate_project_guidelines_callouts(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Task: Delete duplicate callout blocks and add Compliance Checklist section.
    
    Validates:
    1. Only 6 callout blocks remain (one of each type)
    2. Compliance Checklist heading appears after last callout
    3. Exactly 6 unchecked todo items with ☑️ emoji
    4. Divider appears after todos
    5. Paragraph includes today's date and '0 of 6 items verified'
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    # Find Project Guidelines & Best Practices page
    try:
        page_results = final_state_backend.query({
            "collection": "pages",
            "filter": {"title": "Project Guidelines & Best Practices"}
        })
    
        if not page_results:
            # Try alternate title
            page_results = final_state_backend.query({
                "collection": "pages",
                "filter": {"title": "Project Guidelines"}
            })
    
        if not page_results:
            errors.append("[X] Page 'Project Guidelines & Best Practices' not found")
        else:
            checks_passed.append("[C] Page 'Project Guidelines & Best Practices' found")
    
        page_id = page_results[0].get("_id")
    
        # Get all blocks
        all_blocks = final_state_backend.query({
            "collection": "blocks",
            "filter": {"pageId": page_id}
        })
    
        all_blocks.sort(key=lambda b: b.get("order", 0))
    
        # Count callout blocks
        callout_count = sum(1 for block in all_blocks if block.get("type") == "callout")
    
        if callout_count > 6:
            errors.append(f"[X] Expected only 6 callout blocks (duplicates removed), found {callout_count}")
        else:
            checks_passed.append(f"[C] Expected only 6 callout blocks (duplicates removed), found {callout_count}")
    
        # Find Compliance Checklist heading
        compliance_idx = -1
        for idx, block in enumerate(all_blocks):
            if block.get("type") == "heading2":
                content = str(block.get("content", ""))
                if "📋" in content and "Compliance Checklist" in content:
                    compliance_idx = idx
                    break
    
        if compliance_idx == -1:
            errors.append("[X] '📋 Compliance Checklist' heading_2 not found")
        else:
            checks_passed.append("[C] '📋 Compliance Checklist' heading_2 found")
    
        # Check for 6 todos with ☑️ emoji
        expected_todos = [
            "Unit tests written for all new code",
            "No API keys in repository verified",
            "Production deployment approval obtained",
            "TypeScript strict mode enabled",
            "Changelog updated",
            "Security review completed"
        ]
    
        found_todos = 0
        for i in range(compliance_idx + 1, min(compliance_idx + 10, len(all_blocks))):
            if all_blocks[i].get("type") == "todo":
                content = str(all_blocks[i].get("content", ""))
                if "☑️" in content and any(expected in content for expected in expected_todos):
                    found_todos += 1
                    # Check that todo is unchecked
                    if all_blocks[i].get("properties", {}).get("checked", False):
                        errors.append("[X] Compliance checklist todos should be unchecked")
                    else:
                        checks_passed.append("[C] Compliance checklist todos should be unchecked")
    
        if found_todos < 6:
            errors.append(f"[X] Expected 6 unchecked todos with ☑️ emoji, found {found_todos}")
        else:
            checks_passed.append(f"[C] Found 6 unchecked todos with ☑️ emoji as expected")
    
        # Check for divider
        has_divider = False
        for i in range(compliance_idx + 7, min(compliance_idx + 10, len(all_blocks))):
            if all_blocks[i].get("type") == "divider":
                has_divider = True
                break
    
        if not has_divider:
            errors.append("[X] Missing divider after todos")
        else:
            checks_passed.append("[C] has divider after todos")
    
        # Check for compliance check paragraph
        has_check_paragraph = False
        for i in range(compliance_idx + 8, min(compliance_idx + 12, len(all_blocks))):
            if all_blocks[i].get("type") == "paragraph":
                content = str(all_blocks[i].get("content", ""))
                if "Last compliance check:" in content and "0 of 6 items verified" in content:
                    has_check_paragraph = True
                    break
    
        if not has_check_paragraph:
            errors.append("[X] Missing paragraph with 'Last compliance check' and '0 of 6 items verified'")
        else:
            checks_passed.append("[C] has paragraph with 'Last compliance check' and '0 of 6 items verified'")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

    # -----------------------------------------------------------------------------
    # create-feature-development-tracker-v2
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_create_feature_development_tracker(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Task: Create Feature Development Tracker page aggregating bugs and features.
    
    Validates:
    1. Page aggregates data from Feature Requests and Bug Tracker pages
    2. Critical bugs are prefixed with [BUG]
    3. Checked features appear as paragraphs under Ready for Development
    4. Unchecked features as todos under Under Consideration
    5. Code block shows accurate counts
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    # Find Feature Development Tracker page
    try:
        page_results = final_state_backend.query({
            "collection": "pages",
            "filter": {"title": "Feature Development Tracker"}
        })
    
        if not page_results:
            errors.append("[X] Page 'Feature Development Tracker' not found")
        else:
            checks_passed.append("[C] Page 'Feature Development Tracker' found")
    
        page_id = page_results[0].get("_id")
    
        # Get all blocks
        all_blocks = final_state_backend.query({
            "collection": "blocks",
            "filter": {"pageId": page_id}
        })
    
        all_blocks.sort(key=lambda b: b.get("order", 0))
    
        # Check for heading_1
        has_h1 = False
        for block in all_blocks:
            if block.get("type") == "heading1":
                content = str(block.get("content", ""))
                if "🎯" in content and "Feature Development Tracker" in content:
                    has_h1 = True
                    break
    
        if not has_h1:
            errors.append("[X] '🎯 Feature Development Tracker' heading_1 not found")
        else:
            checks_passed.append("[C] '🎯 Feature Development Tracker' heading_1 found")
    
        # Check for Purple callout with Dashboard Overview
        has_callout = False
        for block in all_blocks:
            if block.get("type") == "callout":
                props = block.get("properties", {})
                content = str(block.get("content", ""))
                if props.get("backgroundColor") in ["purple", "purple_background", "Purple"]:
                    if "Dashboard Overview" in content or "Unified view" in content:
                        has_callout = True
                        break
    
        if not has_callout:
            errors.append("[X] Purple callout with 'Dashboard Overview' not found")
        else:
            checks_passed.append("[C] Purple callout with 'Dashboard Overview' found")
    
        # Check for High Priority Items heading
        has_high_priority = False
        for block in all_blocks:
            if block.get("type") == "heading2":
                content = str(block.get("content", ""))
                if "🚨" in content and "High Priority" in content:
                    has_high_priority = True
                    break
    
        if not has_high_priority:
            errors.append("[X] '🚨 High Priority Items' heading_2 not found")
        else:
            checks_passed.append("[C] '🚨 High Priority Items' heading_2 found")
    
        # Check for todos with [BUG] prefix
        bug_todos = 0
        for block in all_blocks:
            if block.get("type") == "todo":
                content = str(block.get("content", ""))
                if "[BUG]" in content:
                    bug_todos += 1
    
        # Check for Feature Pipeline section
        has_feature_pipeline = False
        for block in all_blocks:
            if block.get("type") == "heading2":
                content = str(block.get("content", ""))
                if "✨" in content and "Feature Pipeline" in content:
                    has_feature_pipeline = True
                    break
    
        if not has_feature_pipeline:
            errors.append("[X] '✨ Feature Pipeline' heading_2 not found")
        else:
            checks_passed.append("[C] '✨ Feature Pipeline' heading_2 found")
    
        # Check for subsections
        subsections = ["Ready for Development", "Under Consideration"]
        found_subsections = 0
    
        for block in all_blocks:
            if block.get("type") == "heading3":
                content = str(block.get("content", ""))
                if any(sub in content for sub in subsections):
                    found_subsections += 1
    
        if found_subsections < 2:
            errors.append(f"[X] Expected 2 feature subsections, found {found_subsections}")
        else:
            checks_passed.append(f"[C] Found 2 feature subsections as expected")
    
        # Check for Summary Statistics with code block
        has_summary = False
        has_code_block = False
    
        for block in all_blocks:
            if block.get("type") == "heading2":
                content = str(block.get("content", ""))
                if "📊" in content and "Summary Statistics" in content:
                    has_summary = True
            elif block.get("type") == "code":
                content = str(block.get("content", ""))
                if "Critical Bugs:" in content and "Features" in content and "Total Items:" in content:
                    has_code_block = True
    
        if not has_summary:
            errors.append("[X] '📊 Summary Statistics' heading_2 not found")
        else:
            checks_passed.append("[C] '📊 Summary Statistics' heading_2 found")
    
        if not has_code_block:
            errors.append("[X] Code block with summary statistics not found")
        else:
            checks_passed.append("[C] Code block with summary statistics found")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

    # -----------------------------------------------------------------------------
    # reorganize-engineering-wiki-sections-v2
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_reorganize_engineering_wiki_sections(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Task: Swap Tech Stack and Development Setup sections, add Required Tools section.
    
    Validates:
    1. Development Setup section now appears where Tech Stack was (first position)
    2. Tech Stack section now appears where Development Setup was (second position)
    3. Required Tools section appears between relocated Tech Stack and Environment Variables
    4. Yellow callout has correct icon and text
    5. Numbered list has exactly three specified items
    6. Divider and paragraph with current date at page end (italic not validated due to MCP limitations)
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    # Find Engineering Wiki page
    try:
        page_results = final_state_backend.query({
            "collection": "pages",
            "filter": {"title": "Engineering Wiki"}
        })
    
        if not page_results:
            errors.append("[X] Page 'Engineering Wiki' not found")
        else:
            checks_passed.append("[C] Page 'Engineering Wiki' found")
    
        page_id = page_results[0].get("_id")
    
        # Get all blocks
        all_blocks = final_state_backend.query({
            "collection": "blocks",
            "filter": {"pageId": page_id}
        })
    
        all_blocks.sort(key=lambda b: b.get("order", 0))
    
        # Find key sections
        tech_stack_idx = -1
        dev_setup_idx = -1
        required_tools_idx = -1
        env_var_idx = -1
    
        for idx, block in enumerate(all_blocks):
            content = str(block.get("content", ""))
            block_type = block.get("type")
        
            if "Tech Stack" in content:
                tech_stack_idx = idx
            elif "Development Setup" in content:
                dev_setup_idx = idx
            elif "🔧" in content and "Required Tools" in content:
                required_tools_idx = idx
            elif "Environment Variables" in content:
                env_var_idx = idx
    
        if tech_stack_idx == -1:
            errors.append("[X] Tech Stack section not found")
        else:
            checks_passed.append("[C] Tech Stack section found")
    
        if dev_setup_idx == -1:
            errors.append("[X] Development Setup section not found")
        else:
            checks_passed.append("[C] Development Setup section found")
    
        # Verify sections are swapped (Development Setup should come before Tech Stack)
        if dev_setup_idx >= tech_stack_idx:
            errors.append("[X] Development Setup section should appear before Tech Stack after swapping")
        else:
            checks_passed.append("[C] Development Setup section should appear before Tech Stack after swapping")
    
        # Check for Required Tools section
        if required_tools_idx == -1:
            errors.append("[X] '🔧 Required Tools' heading_2 not found")
        else:
            checks_passed.append("[C] '🔧 Required Tools' heading_2 found")
    
        # Verify Required Tools is between Tech Stack and Environment Variables
        if env_var_idx != -1:
            if required_tools_idx <= tech_stack_idx or required_tools_idx >= env_var_idx:
                errors.append("[X] Required Tools section should be between Tech Stack and Environment Variables")
            else:
                checks_passed.append("[C] Required Tools section should be between Tech Stack and Environment Variables")
    
        # Check for yellow callout with warning icon
        has_callout = False
        for i in range(required_tools_idx + 1, min(required_tools_idx + 3, len(all_blocks))):
            if all_blocks[i].get("type") == "callout":
                props = all_blocks[i].get("properties", {})
                content = str(all_blocks[i].get("content", ""))
                if props.get("backgroundColor") in ["yellow", "yellow_background"] and "⚠️" in props.get("icon", ""):
                    if "Ensure all tools are installed" in content:
                        has_callout = True
                        break
    
        if not has_callout:
            errors.append("[X] Yellow callout with ⚠️ icon and setup text not found")
        else:
            checks_passed.append("[C] Yellow callout with ⚠️ icon and setup text found")
    
        # Check for three numbered list items
        expected_items = [
            "Node.js v18 or higher",
            "Docker Desktop latest version",
            "Git with configured SSH keys"
        ]
    
        found_items = 0
        for i in range(required_tools_idx + 2, min(required_tools_idx + 8, len(all_blocks))):
            if all_blocks[i].get("type") == "numberedList":
                content = str(all_blocks[i].get("content", ""))
                if any(expected in content for expected in expected_items):
                    found_items += 1
    
        if found_items < 3:
            errors.append(f"[X] Expected 3 numbered list items for required tools, found {found_items}")
        else:
            checks_passed.append(f"[C] Found 3 numbered list items for required tools as expected")
    
        # Check for divider and reorganization paragraph at end
        has_divider = False
        has_reorg_paragraph = False
    
        last_blocks = all_blocks[-5:]
        for block in last_blocks:
            if block.get("type") == "divider":
                has_divider = True
            elif block.get("type") == "paragraph":
                content = str(block.get("content", ""))
                if "Last reorganized on" in content:
                    has_reorg_paragraph = True
    
        if not has_divider:
            errors.append("[X] Missing divider at end of page")
        else:
            checks_passed.append("[C] has divider at end of page")
    
        if not has_reorg_paragraph:
            errors.append("[X] Missing paragraph with 'Last reorganized on [date]' at end")
        else:
            checks_passed.append("[C] has paragraph with 'Last reorganized on [date]' at end")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

    # -----------------------------------------------------------------------------
    # add-feature-requests-in-development-v2
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_add_feature_requests_in_development(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Task: Add In Development section with analytics to Feature Requests page.
    
    Validates:
    1. '🚀 In Development' heading2 positioned after High Priority, before Community Suggestions
    2. Three checked todos with specific texts
    3. Analytics section at end with accurate todo counts
    4. Conditional callout (green if >60%, yellow if <=60%)
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    # Find Feature Requests page
    try:
        page_results = final_state_backend.query({
            "collection": "pages",
            "filter": {"title": "Feature Requests"}
        })
    
        if not page_results:
            errors.append("[X] Feature Requests page not found")
        else:
            checks_passed.append("[C] Feature Requests page found")
    
        page = page_results[0]
        # Query blocks collection for this page
        all_blocks = final_state_backend.query({
            "collection": "blocks",
            "filter": {"pageId": page.get("_id")}
        })
    
        # Find '🚀 In Development' heading
        in_dev_idx = None
        for i, block in enumerate(all_blocks):
            if block.get("type") in ["heading2", "heading_2"]:
                content = str(block.get("content", "") or block.get("text", ""))
                if "In Development" in content and "🚀" in content:
                    in_dev_idx = i
                    break
    
        if in_dev_idx is None:
            errors.append("[X] '🚀 In Development' heading not found")
        else:
            checks_passed.append("[C] '🚀 In Development' heading found")
    
        # Check three checked todos after the heading
        expected_todos = [
            "API rate limiting",
            "Webhook integrations",
            "Advanced permissions system"
        ]
    
        found_todos = 0
        for i in range(in_dev_idx + 1, min(in_dev_idx + 5, len(all_blocks))):
            if all_blocks[i].get("type") == "todo":
                content = str(all_blocks[i].get("content", "") or all_blocks[i].get("text", ""))
                checked = all_blocks[i].get("properties", {}).get("checked", False)
                if checked and any(expected in content for expected in expected_todos):
                    found_todos += 1
    
        if found_todos < 3:
            errors.append(f"[X] Expected 3 checked todos in In Development section, found {found_todos}")
        else:
            checks_passed.append(f"[C] Found 3 checked todos in In Development section as expected")
    
        # Count all todos on page
        all_todos = [b for b in all_blocks if b.get("type") == "todo"]
        completed_todos = [t for t in all_todos if t.get("properties", {}).get("checked", False)]
        completion_pct = (len(completed_todos) / len(all_todos) * 100) if all_todos else 0
    
        # Check for analytics section
        has_analytics_heading = False
        has_analytics_bullets = False
        has_conditional_callout = False
    
        for i, block in enumerate(all_blocks):
            if block.get("type") == "heading3":
                content = str(block.get("content", "") or block.get("text", ""))
                if "Feature Request Analytics" in content:
                    has_analytics_heading = True
                    # Check for bulleted analytics
                    for j in range(i + 1, min(i + 6, len(all_blocks))):
                        if all_blocks[j].get("type") == "bulletedList":
                            has_analytics_bullets = True
                            break
        
            if block.get("type") == "callout":
                bg = block.get("properties", {}).get("backgroundColor", "")
                content = str(block.get("content", "") or block.get("text", ""))
                if completion_pct > 60 and "green" in bg.lower() and "Great progress" in content:
                    has_conditional_callout = True
                elif completion_pct <= 60 and "yellow" in bg.lower() and "Accelerate" in content:
                    has_conditional_callout = True
    
        if not has_analytics_heading:
            errors.append("[X] Analytics section heading not found")
        else:
            checks_passed.append("[C] Analytics section heading found")
    
        if not has_analytics_bullets:
            errors.append("[X] Analytics bulleted list not found")
        else:
            checks_passed.append("[C] Analytics bulleted list found")
    
        if not has_conditional_callout:
            errors.append(f"[X] Conditional callout not found or incorrect (completion: {completion_pct:.1f}%)")
        else:
            checks_passed.append(f"[C] Conditional callout found or incorrect (completion: {completion_pct:.1f}%)")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

    # -----------------------------------------------------------------------------
    # add-prd-overview-critical-updates-v2
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_add_prd_overview_critical_updates(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Task: Add Critical Updates section to PRD between Overview Part 2 and Part 3.
    
    Validates:
    1. 'Overview - Critical Updates' heading3 exists between Part 2 and Part 3
    2. Red callout with ⚠️ icon and urgent text
    3. Three specific bulleted items
    4. All 'Key point 1 for Overview' bullets updated with 🔸 prefix
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    # Find Comprehensive Product Requirements Document page
    try:
        page_results = final_state_backend.query({
            "collection": "pages",
            "filter": {"title": "Comprehensive Product Requirements Document"}
        })
    
        if not page_results:
            errors.append("[X] Comprehensive Product Requirements Document page not found")
        else:
            checks_passed.append("[C] Comprehensive Product Requirements Document page found")
    
        page = page_results[0]
        # Query blocks collection for this page
        all_blocks = final_state_backend.query({
            "collection": "blocks",
            "filter": {"pageId": page.get("_id")}
        })
    
        # Find Overview - Part 2 and Part 3 headings
        part2_idx = None
        part3_idx = None
        critical_updates_idx = None
    
        for i, block in enumerate(all_blocks):
            if block.get("type") in ["heading3", "heading_3"]:
                content = str(block.get("content", "") or block.get("text", ""))
                if "Overview - Part 2" in content:
                    part2_idx = i
                elif "Overview - Part 3" in content:
                    part3_idx = i
                elif "Overview - Critical Updates" in content:
                    critical_updates_idx = i
    
        if part2_idx is None or part3_idx is None:
            errors.append("[X] Overview Part 2 or Part 3 headings not found")
        else:
            checks_passed.append("[C] Overview Part 2 or Part 3 headings found")
    
        if critical_updates_idx is None:
            errors.append("[X] 'Overview - Critical Updates' heading not found")
        else:
            checks_passed.append("[C] 'Overview - Critical Updates' heading found")
    
        # Verify positioning
        if not (part2_idx < critical_updates_idx < part3_idx):
            errors.append("[X] Critical Updates section not positioned between Part 2 and Part 3")
        else:
            checks_passed.append("[C] Critical Updates section positioned between Part 2 and Part 3")
    
        # Check for red callout after Critical Updates heading
        has_red_callout = False
        for i in range(critical_updates_idx + 1, min(critical_updates_idx + 3, len(all_blocks))):
            if all_blocks[i].get("type") == "callout":
                bg = all_blocks[i].get("properties", {}).get("backgroundColor", "")
                icon = all_blocks[i].get("properties", {}).get("icon", "")
                content = str(all_blocks[i].get("content", "") or all_blocks[i].get("text", ""))
                if "red" in bg.lower() and "⚠" in (icon or content) and "URGENT" in content:
                    has_red_callout = True
                    break
    
        if not has_red_callout:
            errors.append("[X] Red callout with ⚠️ icon and URGENT text not found")
        else:
            checks_passed.append("[C] Red callout with ⚠️ icon and URGENT text found")
    
        # Check for three specific bullets
        expected_bullets = [
            "No further modifications without VP approval",
            "Implementation deadline: Q2 2026",
            "Stakeholder sign-off required by EOW"
        ]
    
        found_bullets = 0
        for i in range(critical_updates_idx + 1, min(critical_updates_idx + 8, len(all_blocks))):
            if all_blocks[i].get("type") == "bulletedList":
                content = str(all_blocks[i].get("content", "") or all_blocks[i].get("text", ""))
                if any(expected in content for expected in expected_bullets):
                    found_bullets += 1
    
        if found_bullets < 3:
            errors.append(f"[X] Expected 3 specific bulleted items, found {found_bullets}")
        else:
            checks_passed.append(f"[C] Found 3 specific bulleted items as expected")
    
        # Check for 🔸 prefix on Key point 1 bullets
        key_point_bullets = [b for b in all_blocks if b.get("type") == "bulletedList" and "Key point 1 for Overview" in str(b.get("content", "") or b.get("text", ""))]
    
        if key_point_bullets:
            updated_count = sum(1 for b in key_point_bullets if "🔸" in str(b.get("content", "") or b.get("text", "")))
            if updated_count < len(key_point_bullets):
                errors.append(f"[X] Not all 'Key point 1 for Overview' bullets have 🔸 prefix ({updated_count}/{len(key_point_bullets)})")
            else:
                checks_passed.append(f"[C] all 'Key point 1 for Overview' bullets have 🔸 prefix ({updated_count}/{len(key_point_bullets)})")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

    # -----------------------------------------------------------------------------
    # create-design-system-resources-v2
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_create_design_system_resources(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Task: Create three child pages under Design System and add Design Resources section.
    
    Validates:
    1. Three new child pages with exact titles and emojis
    2. '📚 Design Resources' heading added to main page
    3. Three bookmark blocks with exact captions
    4. Purple callout with date
    5. Original child pages moved under Component Library
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    # Find Design System page
    try:
        design_system_results = final_state_backend.query({
            "collection": "pages",
            "filter": {"title": "Design System"}
        })
    
        if not design_system_results:
            errors.append("[X] Design System page not found")
        else:
            checks_passed.append("[C] Design System page found")
    
        design_system_id = design_system_results[0].get("_id")
        # Query blocks collection for this page
        all_blocks = final_state_backend.query({
            "collection": "blocks",
            "filter": {"pageId": design_system_id}
        })
    
        # Check for three new child pages
        expected_pages = [
            "🎨 Color Guidelines",
            "📐 Layout Grids",
            "🧩 Component Library"
        ]
    
        found_pages = []
        for expected in expected_pages:
            page_results = final_state_backend.query({
                "collection": "pages",
                "filter": {"title": expected}
            })
            if page_results:
                found_pages.append(expected)
    
        if len(found_pages) < 3:
            missing = [p for p in expected_pages if p not in found_pages]
            errors.append(f"[X] Missing child pages: {', '.join(missing)}")
        else:
            checks_passed.append(f"[C] has child pages")
    
        # Check for Design Resources heading
        has_resources_heading = False
        for block in all_blocks:
            if block.get("type") in ["heading2", "heading_2"]:
                content = str(block.get("content", "") or block.get("text", ""))
                if "Design Resources" in content and "📚" in content:
                    has_resources_heading = True
                    break
    
        if not has_resources_heading:
            errors.append("[X] '📚 Design Resources' heading not found")
        else:
            checks_passed.append("[C] '📚 Design Resources' heading found")
    
        # Check for bookmark blocks
        bookmarks = [b for b in all_blocks if b.get("type") == "bookmark"]
    
        if len(bookmarks) < 3:
            errors.append(f"[X] Expected 3 bookmark blocks, found {len(bookmarks)}")
        else:
            checks_passed.append(f"[C] Found 3 bookmark blocks as expected")
    
        # Check for purple callout
        has_purple_callout = False
        for block in all_blocks:
            if block.get("type") == "callout":
                bg = block.get("properties", {}).get("backgroundColor", "")
                icon = block.get("properties", {}).get("icon", "")
                content = str(block.get("content", "") or block.get("text", ""))
                if "purple" in bg.lower() and "🎨" in (icon or content) and "Last updated" in content:
                    has_purple_callout = True
                    break
    
        if not has_purple_callout:
            errors.append("[X] Purple callout with 🎨 icon and 'Last updated' not found")
        else:
            checks_passed.append("[C] Purple callout with 🎨 icon and 'Last updated' found")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

    # -----------------------------------------------------------------------------
    # add-bug-tracker-in-progress-v2
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_add_bug_tracker_in_progress(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Task: Add In Progress section to Bug Tracker between Medium and Low Priority.
    
    Validates:
    1. 'In Progress' heading2 positioned correctly
    2. Three unchecked todos with specific texts
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    # Find Bug Tracker page
    try:
        page_results = final_state_backend.query({
            "collection": "pages",
            "filter": {"title": "Bug Tracker"}
        })
    
        if not page_results:
            errors.append("[X] Bug Tracker page not found")
        else:
            checks_passed.append("[C] Bug Tracker page found")
    
        page = page_results[0]
        # Query blocks collection for this page
        all_blocks = final_state_backend.query({
            "collection": "blocks",
            "filter": {"pageId": page.get("_id")}
        })
    
        # Find section headings
        medium_idx = None
        low_idx = None
        in_progress_idx = None
    
        for i, block in enumerate(all_blocks):
            if block.get("type") in ["heading2", "heading_2"]:
                content = str(block.get("content", "") or block.get("text", ""))
                if "Medium Priority" in content:
                    medium_idx = i
                elif "Low Priority" in content:
                    low_idx = i
                elif "In Progress" in content:
                    in_progress_idx = i
    
        if medium_idx is None or low_idx is None:
            errors.append("[X] Medium Priority or Low Priority headings not found")
        else:
            checks_passed.append("[C] Medium Priority or Low Priority headings found")
    
        if in_progress_idx is None:
            errors.append("[X] 'In Progress' heading not found")
        else:
            checks_passed.append("[C] 'In Progress' heading found")
    
        # Verify positioning (should be between Medium and Low)
        if not (medium_idx < in_progress_idx < low_idx):
            errors.append(f"[X] 'In Progress' section not positioned between Medium and Low Priority")
        else:
            checks_passed.append(f"[C] 'In Progress' section positioned between Medium and Low Priority")
    
        # Check for three unchecked todos
        expected_todos = [
            "Fix notification system delay on iOS",
            "Debug memory leak in image uploader",
            "Optimize database query for user search"
        ]
    
        found_todos = 0
        for i in range(in_progress_idx + 1, min(in_progress_idx + 5, len(all_blocks))):
            if all_blocks[i].get("type") == "todo":
                content = str(all_blocks[i].get("content", "") or all_blocks[i].get("text", ""))
                is_checked = all_blocks[i].get("properties", {}).get("checked", True)
                if not is_checked and any(expected in content for expected in expected_todos):
                    found_todos += 1
    
        if found_todos < 3:
            errors.append(f"[X] Expected 3 unchecked todos in In Progress section, found {found_todos}")
        else:
            checks_passed.append(f"[C] Found 3 unchecked todos in In Progress section as expected")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

    # -----------------------------------------------------------------------------
    # add-getting-started-checklist-items-v2
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_add_getting_started_checklist_items(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Task: Insert two new todos in Getting Started checklist and add tip callout.
    
    Validates:
    1. Two new todos inserted between specified existing todos
    2. Blue callout with 💡 icon after checklist
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    # Find Getting Started page
    try:
        page_results = final_state_backend.query({
            "collection": "pages",
            "filter": {"title": "Getting Started"}
        })
    
        if not page_results:
            errors.append("[X] Getting Started page not found")
        else:
            checks_passed.append("[C] Getting Started page found")
    
        page = page_results[0]
        # Query blocks collection for this page
        all_blocks = final_state_backend.query({
            "collection": "blocks",
            "filter": {"pageId": page.get("_id")}
        })
    
        # Find todos with specific texts
        dashboard_todo = None
        notification_todo = None
    
        for block in all_blocks:
            if block.get("type") == "todo":
                content = str(block.get("content", "") or block.get("text", ""))
                if "Review the team dashboard" in content and "📊" in content:
                    dashboard_todo = block
                elif "Set up your notification preferences" in content and "🔔" in content:
                    notification_todo = block
    
        if dashboard_todo is None:
            errors.append("[X] New todo '📊 Review the team dashboard' not found")
        else:
            checks_passed.append("[C] New todo '📊 Review the team dashboard' found")
    
        if notification_todo is None:
            errors.append("[X] New todo '🔔 Set up your notification preferences' not found")
        else:
            checks_passed.append("[C] New todo '🔔 Set up your notification preferences' found")
    
        # Check for blue callout with tip
        has_tip_callout = False
        for block in all_blocks:
            if block.get("type") == "callout":
                bg = block.get("properties", {}).get("backgroundColor", "")
                icon = block.get("properties", {}).get("icon", "")
                content = str(block.get("content", "") or block.get("text", ""))
                if "blue" in bg.lower() and "💡" in (icon or content) and "Tip:" in content and "onboarding" in content.lower():
                    has_tip_callout = True
                    break
    
        if not has_tip_callout:
            errors.append("[X] Blue callout with 💡 icon and tip text not found")
        else:
            checks_passed.append("[C] Blue callout with 💡 icon and tip text found")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

    # -----------------------------------------------------------------------------
    # add-sprint-velocity-calculation-v2
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_add_sprint_velocity_calculation(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Task: Add Sprint Velocity Calculation section to Sprint Planning page.
    
    Validates:
    1. '📈 Sprint Velocity Calculation' heading at bottom
    2. Blue callout with Sprint Metrics
    3. Bulleted list with calculations
    4. Emoji-based progress bar
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    # Find Sprint Planning - Jan 15 page
    try:
        page_results = final_state_backend.query({
            "collection": "pages",
            "filter": {"title": "Sprint Planning - Jan 15"}
        })
    
        if not page_results:
            errors.append("[X] Sprint Planning - Jan 15 page not found")
        else:
            checks_passed.append("[C] Sprint Planning - Jan 15 page found")
    
        page = page_results[0]
        # Query blocks collection for this page
        all_blocks = final_state_backend.query({
            "collection": "blocks",
            "filter": {"pageId": page.get("_id")}
        })
    
        # Check for Sprint Velocity Calculation heading
        has_velocity_heading = False
        for block in all_blocks:
            if block.get("type") in ["heading2", "heading_2"]:
                content = str(block.get("content", "") or block.get("text", ""))
                if "Sprint Velocity Calculation" in content and "📈" in content:
                    has_velocity_heading = True
                    break
    
        if not has_velocity_heading:
            errors.append("[X] '📈 Sprint Velocity Calculation' heading not found")
        else:
            checks_passed.append("[C] '📈 Sprint Velocity Calculation' heading found")
    
        # Check for blue callout with Sprint Metrics
        has_metrics_callout = False
        for block in all_blocks:
            if block.get("type") == "callout":
                bg = block.get("properties", {}).get("backgroundColor", "")
                icon = block.get("properties", {}).get("icon", "")
                content = str(block.get("content", "") or block.get("text", ""))
                if "blue" in bg.lower() and "🧮" in (icon or content) and "Sprint Metrics" in content:
                    has_metrics_callout = True
                    break
    
        if not has_metrics_callout:
            errors.append("[X] Blue callout with 🧮 icon and 'Sprint Metrics' not found")
        else:
            checks_passed.append("[C] Blue callout with 🧮 icon and 'Sprint Metrics' found")
    
        # Check for bulleted list with velocity metrics
        has_velocity_bullets = False
        for block in all_blocks:
            if block.get("type") == "bulletedList":
                content = str(block.get("content", "") or block.get("text", ""))
                if "Story points" in content or "velocity" in content.lower():
                    has_velocity_bullets = True
                    break
    
        if not has_velocity_bullets:
            errors.append("[X] Bulleted list with velocity metrics not found")
        else:
            checks_passed.append("[C] Bulleted list with velocity metrics found")
    
        # Check for emoji progress bar
        has_progress_bar = False
        for block in all_blocks:
            content = str(block.get("content", "") or block.get("text", ""))
            if ("🟦" in content or "⬜" in content) and "capacity" in content.lower():
                has_progress_bar = True
                break
    
        if not has_progress_bar:
            errors.append("[X] Emoji-based progress bar not found")
        else:
            checks_passed.append("[C] Emoji-based progress bar found")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

    # -----------------------------------------------------------------------------
    # create-documentation-index-v2
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_create_documentation_index(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Task: Create Documentation Index page as sibling to Project Documentation.
    
    Validates:
    1. '📚 Documentation Index' page exists at correct level
    2. Proper heading structure
    3. Entries for all pages with block counts
    4. Statistics callout with purple background
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    # Find Project Documentation page
    try:
        proj_doc_results = final_state_backend.query({
            "collection": "pages",
            "filter": {"title": "Project Documentation"}
        })
    
        if not proj_doc_results:
            errors.append("[X] Project Documentation page not found")
        else:
            checks_passed.append("[C] Project Documentation page found")
    
        proj_doc_parent = proj_doc_results[0].get("parentId")
    
        # Find Documentation Index page
        index_results = final_state_backend.query({
            "collection": "pages",
            "filter": {"title": "📚 Documentation Index"}
        })
    
        if not index_results:
            errors.append("[X] '📚 Documentation Index' page not found")
        else:
            checks_passed.append("[C] '📚 Documentation Index' page found")
    
        index_page = index_results[0]
    
        # Verify it's a sibling (same parent)
        if index_page.get("parentId") != proj_doc_parent:
            errors.append("[X] Documentation Index is not a sibling of Project Documentation")
        else:
            checks_passed.append("[C] Documentation Index is a sibling of Project Documentation")
    
        # Query blocks collection for this page
        all_blocks = final_state_backend.query({
            "collection": "blocks",
            "filter": {"pageId": index_page.get("_id")}
        })
    
        # Check for main heading
        has_main_heading = False
        for block in all_blocks:
            if block.get("type") in ["heading1", "heading_1"]:
                content = str(block.get("content", "") or block.get("text", ""))
                if "Complete Documentation Index" in content and "📚" in content:
                    has_main_heading = True
                    break
    
        if not has_main_heading:
            errors.append("[X] Main heading '📚 Complete Documentation Index' not found")
        else:
            checks_passed.append("[C] Main heading '📚 Complete Documentation Index' found")
    
        # Check for Documentation Structure heading
        has_structure_heading = False
        for block in all_blocks:
            if block.get("type") in ["heading2", "heading_2"]:
                content = str(block.get("content", "") or block.get("text", ""))
                if "Documentation Structure" in content and "🗂" in content:
                    has_structure_heading = True
                    break
    
        if not has_structure_heading:
            errors.append("[X] '🗂️ Documentation Structure' heading not found")
        else:
            checks_passed.append("[C] '🗂️ Documentation Structure' heading found")
    
        # Check for Statistics heading and callout
        has_stats_heading = False
        has_purple_callout = False
    
        for block in all_blocks:
            if block.get("type") in ["heading2", "heading_2"]:
                content = str(block.get("content", "") or block.get("text", ""))
                if "Statistics" in content and "📊" in content:
                    has_stats_heading = True
        
            if block.get("type") == "callout":
                bg = block.get("properties", {}).get("backgroundColor", "")
                content = str(block.get("content", "") or block.get("text", ""))
                if "purple" in bg.lower() and "Total Pages:" in content and "Average" in content:
                    has_purple_callout = True
    
        if not has_stats_heading:
            errors.append("[X] '📊 Statistics' heading not found")
        else:
            checks_passed.append("[C] '📊 Statistics' heading found")
    
        if not has_purple_callout:
            errors.append("[X] Purple statistics callout not found")
        else:
            checks_passed.append("[C] Purple statistics callout found")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

    # -----------------------------------------------------------------------------
    # reorganize-onboarding-add-milestones-v2
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_reorganize_onboarding_add_milestones(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Task: Swap sections in Onboarding Guide and add 30-Day Milestones.
    
    Validates:
    1. First Week Goals appears before First Day Tasks
    2. 30-Day Milestones section with three todos
    3. Team Directory image at end with caption
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    # Find Onboarding Guide page
    try:
        page_results = final_state_backend.query({
            "collection": "pages",
            "filter": {"title": "Onboarding Guide"}
        })
    
        if not page_results:
            errors.append("[X] Onboarding Guide page not found")
        else:
            checks_passed.append("[C] Onboarding Guide page found")
    
        page = page_results[0]
        # Query blocks collection for this page
        all_blocks = final_state_backend.query({
            "collection": "blocks",
            "filter": {"pageId": page.get("_id")}
        })
    
        # Find section headings
        first_day_idx = None
        first_week_idx = None
        milestones_idx = None
    
        for i, block in enumerate(all_blocks):
            if block.get("type") in ["heading2", "heading_2"]:
                content = str(block.get("content", "") or block.get("text", ""))
                if "First Day Tasks" in content:
                    first_day_idx = i
                elif "First Week Goals" in content:
                    first_week_idx = i
                elif "30-Day Milestones" in content and "🎯" in content:
                    milestones_idx = i
    
        if first_day_idx is None or first_week_idx is None:
            errors.append("[X] First Day Tasks or First Week Goals headings not found")
        else:
            checks_passed.append("[C] First Day Tasks or First Week Goals headings found")
    
        # Verify sections are swapped (First Week should come before First Day)
        if first_week_idx >= first_day_idx:
            errors.append("[X] Sections not swapped: First Week Goals should appear before First Day Tasks")
        else:
            checks_passed.append("[C] Sections swapped: First Week Goals should appear before First Day Tasks")
    
        if milestones_idx is None:
            errors.append("[X] '🎯 30-Day Milestones' heading not found")
        else:
            checks_passed.append("[C] '🎯 30-Day Milestones' heading found")
    
        # Verify 30-Day Milestones is positioned after First Day Tasks
        if milestones_idx <= first_day_idx:
            errors.append("[X] 30-Day Milestones should appear after First Day Tasks")
        else:
            checks_passed.append("[C] 30-Day Milestones should appear after First Day Tasks")
    
        # Check for three todos in 30-Day Milestones
        expected_todos = [
            "Complete product deep-dive training",
            "Shadow customer support for one day",
            "Present learnings to the team"
        ]
    
        found_todos = 0
        for i in range(milestones_idx + 1, min(milestones_idx + 6, len(all_blocks))):
            if all_blocks[i].get("type") == "todo":
                content = str(all_blocks[i].get("content", "") or all_blocks[i].get("text", ""))
                if any(expected in content for expected in expected_todos):
                    found_todos += 1
    
        if found_todos < 3:
            errors.append(f"[X] Expected 3 todos in 30-Day Milestones, found {found_todos}")
        else:
            checks_passed.append(f"[C] Found 3 todos in 30-Day Milestones as expected")
    
        # Check for image at end with caption
        has_image_with_caption = False
        for i in range(len(all_blocks) - 5, len(all_blocks)):
            if i >= 0 and all_blocks[i].get("type") == "image":
                # Check for caption in next few blocks
                for j in range(i + 1, min(i + 3, len(all_blocks))):
                    if all_blocks[j].get("type") == "paragraph":
                        content = str(all_blocks[j].get("content", "") or all_blocks[j].get("text", ""))
                        if "Meet your new colleagues" in content:
                            has_image_with_caption = True
                            break
    
        if not has_image_with_caption:
            errors.append("[X] Image with 'Meet your new colleagues!' caption not found at end")
        else:
            checks_passed.append("[C] Image with 'Meet your new colleagues!' caption found at end")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

    # -----------------------------------------------------------------------------
    # add-sprint-planning-priority-tasks-v2
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_add_sprint_planning_priority_tasks(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Task: Add Priority Tasks section to Sprint Planning page.
    
    Validates:
    1. '🎯 Priority Tasks' heading after Action Items
    2. Three unchecked todos with specific texts
    3. Divider after todos
    4. Italic paragraph with current date
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    # Find Sprint Planning - Jan 15 page
    try:
        page_results = final_state_backend.query({
            "collection": "pages",
            "filter": {"title": "Sprint Planning - Jan 15"}
        })
    
        if not page_results:
            errors.append("[X] Sprint Planning - Jan 15 page not found")
        else:
            checks_passed.append("[C] Sprint Planning - Jan 15 page found")
    
        page = page_results[0]
        # Query blocks collection for this page
        all_blocks = final_state_backend.query({
            "collection": "blocks",
            "filter": {"pageId": page.get("_id")}
        })
    
        # Find Action Items and Priority Tasks headings
        action_items_idx = None
        priority_tasks_idx = None
    
        for i, block in enumerate(all_blocks):
            if block.get("type") in ["heading2", "heading_2"]:
                content = str(block.get("content", "") or block.get("text", ""))
                if "Action Items" in content:
                    action_items_idx = i
                elif "Priority Tasks" in content and "🎯" in content:
                    priority_tasks_idx = i
    
        if action_items_idx is None:
            errors.append("[X] Action Items heading not found")
        else:
            checks_passed.append("[C] Action Items heading found")
    
        if priority_tasks_idx is None:
            errors.append("[X] '🎯 Priority Tasks' heading not found")
        else:
            checks_passed.append("[C] '🎯 Priority Tasks' heading found")
    
        # Verify positioning (Priority Tasks should be after Action Items)
        if priority_tasks_idx <= action_items_idx:
            errors.append("[X] Priority Tasks should appear after Action Items heading")
        else:
            checks_passed.append("[C] Priority Tasks should appear after Action Items heading")
    
        # Check for three unchecked todos
        expected_todos = [
            "URGENT: Fix authentication bug in production",
            "HIGH: Complete API performance optimization",
            "MEDIUM: Implement analytics dashboard"
        ]
    
        found_todos = 0
        for i in range(priority_tasks_idx + 1, min(priority_tasks_idx + 5, len(all_blocks))):
            if all_blocks[i].get("type") == "todo":
                content = str(all_blocks[i].get("content", "") or all_blocks[i].get("text", ""))
                is_checked = all_blocks[i].get("properties", {}).get("checked", True)
                if not is_checked and any(expected in content for expected in expected_todos):
                    found_todos += 1
    
        if found_todos < 3:
            errors.append(f"[X] Expected 3 unchecked priority todos, found {found_todos}")
        else:
            checks_passed.append(f"[C] Found 3 unchecked priority todos as expected")
    
        # Check for divider after Priority Tasks section
        has_divider = False
        for i in range(priority_tasks_idx + 1, min(priority_tasks_idx + 8, len(all_blocks))):
            if all_blocks[i].get("type") == "divider":
                has_divider = True
                break
    
        if not has_divider:
            errors.append("[X] Divider not found after Priority Tasks todos")
        else:
            checks_passed.append("[C] Divider found after Priority Tasks todos")
    
        # Check for italic paragraph with date
        has_date_paragraph = False
        for i in range(priority_tasks_idx + 1, min(priority_tasks_idx + 10, len(all_blocks))):
            if all_blocks[i].get("type") == "paragraph":
                content = str(all_blocks[i].get("content", "") or all_blocks[i].get("text", ""))
                if "Last review:" in content:
                    has_date_paragraph = True
                    break
    
        if not has_date_paragraph:
            errors.append("[X] Italic paragraph with 'Last review: [date]' not found")
        else:
            checks_passed.append("[C] Italic paragraph with 'Last review: [date]' found")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

    # -----------------------------------------------------------------------------
    # add-api-authentication-methods-v2
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_add_api_authentication_methods(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Task: Add Authentication Methods section to API Documentation.
    
    Validates:
    1. '🔐 Authentication Methods' heading at end
    2. Yellow callout with 🔑 icon
    3. Three heading3 blocks for auth types
    4. Code block with javascript language
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    # Find API Documentation page
    try:
        page_results = final_state_backend.query({
            "collection": "pages",
            "filter": {"title": "API Documentation"}
        })
    
        if not page_results:
            errors.append("[X] API Documentation page not found")
        else:
            checks_passed.append("[C] API Documentation page found")
    
        page = page_results[0]
        # Query blocks collection for this page
        all_blocks = final_state_backend.query({
            "collection": "blocks",
            "filter": {"pageId": page.get("_id")}
        })
    
        # Check for Authentication Methods heading
        has_auth_heading = False
        for block in all_blocks:
            if block.get("type") in ["heading2", "heading_2"]:
                content = str(block.get("content", "") or block.get("text", ""))
                if "Authentication Methods" in content and "🔐" in content:
                    has_auth_heading = True
                    break
    
        if not has_auth_heading:
            errors.append("[X] '🔐 Authentication Methods' heading not found")
        else:
            checks_passed.append("[C] '🔐 Authentication Methods' heading found")
    
        # Check for yellow callout
        has_yellow_callout = False
        for block in all_blocks:
            if block.get("type") == "callout":
                bg = block.get("properties", {}).get("backgroundColor", "")
                icon = block.get("properties", {}).get("icon", "")
                content = str(block.get("content", "") or block.get("text", ""))
                if "yellow" in bg.lower() and "🔑" in (icon or content) and "authentication headers" in content.lower():
                    has_yellow_callout = True
                    break
    
        if not has_yellow_callout:
            errors.append("[X] Yellow callout with 🔑 icon not found")
        else:
            checks_passed.append("[C] Yellow callout with 🔑 icon found")
    
        # Check for three auth type headings
        auth_headings = []
        for block in all_blocks:
            if block.get("type") in ["heading3", "heading_3"]:
                content = str(block.get("content", "") or block.get("text", ""))
                if any(auth in content for auth in ["API Key", "OAuth", "JWT"]):
                    auth_headings.append(content)
    
        if len(auth_headings) < 3:
            errors.append(f"[X] Expected 3 authentication type headings, found {len(auth_headings)}")
        else:
            checks_passed.append(f"[C] Found 3 authentication type headings as expected")
    
        # Check for code block with javascript
        has_js_code = False
        for block in all_blocks:
            if block.get("type") == "code":
                lang = block.get("properties", {}).get("language", "")
                content = str(block.get("content", "") or block.get("text", ""))
                if "javascript" in lang.lower() and "X-API-Key" in content:
                    has_js_code = True
                    break
    
        if not has_js_code:
            errors.append("[X] JavaScript code block with API key header not found")
        else:
            checks_passed.append("[C] JavaScript code block with API key header found")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

    # -----------------------------------------------------------------------------
    # add-code-examples-go-section-v2
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_add_code_examples_go_section(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Task: Add Go Examples section to Code Examples Repository.
    
    Validates:
    1. 'Go Examples' heading between Python and Typescript
    2. Code block with 'go' language
    3. Paragraph about go patterns
    4. Additional Resources section with bookmark
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    # Find Code Examples Repository page
    try:
        page_results = final_state_backend.query({
            "collection": "pages",
            "filter": {"title": "Code Examples Repository"}
        })
    
        if not page_results:
            errors.append("[X] Code Examples Repository page not found")
        else:
            checks_passed.append("[C] Code Examples Repository page found")
    
        page = page_results[0]
        # Query blocks collection for this page
        all_blocks = final_state_backend.query({
            "collection": "blocks",
            "filter": {"pageId": page.get("_id")}
        })
    
        # Find section headings
        python_idx = None
        typescript_idx = None
        go_idx = None
    
        for i, block in enumerate(all_blocks):
            if block.get("type") in ["heading2", "heading_2"]:
                content = str(block.get("content", "") or block.get("text", ""))
                if "Python Examples" in content:
                    python_idx = i
                elif "Typescript Examples" in content or "TypeScript Examples" in content:
                    typescript_idx = i
                elif "Go Examples" in content and go_idx is None:
                    go_idx = i
    
        if python_idx is None or typescript_idx is None:
            errors.append("[X] Python Examples or Typescript Examples headings not found")
        else:
            checks_passed.append("[C] Python Examples or Typescript Examples headings found")
    
        if go_idx is None:
            errors.append("[X] 'Go Examples' heading not found")
        else:
            checks_passed.append("[C] 'Go Examples' heading found")
    
        # Verify positioning (Go should be between Python and Typescript)
        if not (python_idx < go_idx < typescript_idx):
            errors.append("[X] Go Examples section not positioned between Python and Typescript")
        else:
            checks_passed.append("[C] Go Examples section positioned between Python and Typescript")
    
        # Check for go code block
        has_go_code = False
        for i in range(go_idx + 1, min(go_idx + 5, len(all_blocks))):
            if all_blocks[i].get("type") == "code":
                lang = all_blocks[i].get("properties", {}).get("language", "")
                content = str(all_blocks[i].get("content", "") or all_blocks[i].get("text", ""))
                if "go" in lang.lower() and "processData" in content:
                    has_go_code = True
                    break
    
        if not has_go_code:
            errors.append("[X] Go code block with processData function not found")
        else:
            checks_passed.append("[C] Go code block with processData function found")
    
        # Check for Additional Resources section
        has_resources = False
        has_go_bookmark = False
    
        for block in all_blocks:
            if block.get("type") in ["heading2", "heading_2"]:
                content = str(block.get("content", "") or block.get("text", ""))
                if "Additional Resources" in content and "📚" in content:
                    has_resources = True
        
            if block.get("type") == "bookmark":
                url = block.get("properties", {}).get("url", "")
                if "go.dev" in url.lower():
                    has_go_bookmark = True
    
        if not has_resources:
            errors.append("[X] '📚 Additional Resources' heading not found")
        else:
            checks_passed.append("[C] '📚 Additional Resources' heading found")
    
        if not has_go_bookmark:
            errors.append("[X] Bookmark to go.dev documentation not found")
        else:
            checks_passed.append("[C] Bookmark to go.dev documentation found")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

    # -----------------------------------------------------------------------------
    # add-handbook-navigation-system-v2
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_add_handbook_navigation_system(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Task: Add comprehensive navigation system to Company Handbook.
    
    Validates:
    1. Table of Contents at beginning with bulleted list of all heading2 sections
    2. Gray callouts for sections with >5 blocks
    3. Development notices for sections with <3 blocks
    4. Revision History at end with 4 quarterly todos
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    # Find Company Handbook page
    try:
        page_results = final_state_backend.query({
            "collection": "pages",
            "filter": {"title": "Company Handbook"}
        })
    
        if not page_results:
            errors.append("[X] Company Handbook page not found")
        else:
            checks_passed.append("[C] Company Handbook page found")
    
        page = page_results[0]
        # Query blocks collection for this page
        all_blocks = final_state_backend.query({
            "collection": "blocks",
            "filter": {"pageId": page.get("_id")}
        })
    
        # Find Table of Contents heading and collect all heading2 sections
        toc_idx = None
        heading2_sections = []
    
        for i, block in enumerate(all_blocks):
            if block.get("type") in ["heading2", "heading_2"]:
                content = str(block.get("content", "") or block.get("text", ""))
                if "Table of Contents" in content and "📑" in content:
                    toc_idx = i
                else:
                    heading2_sections.append((i, content))
    
        if toc_idx is None:
            errors.append("[X] '📑 Table of Contents' heading not found at beginning")
        else:
            checks_passed.append("[C] '📑 Table of Contents' heading found at beginning")
    
        # Check bulleted list after TOC contains all heading2 sections (excluding TOC and Revision History)
        non_toc_sections = [name for idx, name in heading2_sections if "Table of Contents" not in name and "Revision History" not in name]
    
        toc_bullets = []
        for i in range(toc_idx + 1, min(toc_idx + 10, len(all_blocks))):
            if all_blocks[i].get("type") == "bulletedList":
                toc_bullets.append(str(all_blocks[i].get("content", "") or all_blocks[i].get("text", "")))
            elif all_blocks[i].get("type") in ["heading2", "heading_2", "heading1", "heading_1"]:
                break
    
        if len(toc_bullets) < len(non_toc_sections):
            errors.append(f"[X] TOC should have {len(non_toc_sections)} bulleted items for sections, found {len(toc_bullets)}")
        else:
            checks_passed.append(f"[C] TOC should have {len(non_toc_sections)} bulleted items for sections, found {len(toc_bullets)}")
    
        # Check each section for callouts (>5 blocks) or development notices (<3 blocks)
        for section_idx, (section_pos, section_name) in enumerate(heading2_sections):
            if "Table of Contents" in section_name or "Revision History" in section_name:
                continue
        
            # Find the next heading2 to determine section boundaries
            next_section_pos = len(all_blocks)
            for next_idx, next_name in heading2_sections[section_idx + 1:]:
                next_section_pos = next_idx
                break
        
            # Count blocks in this section (excluding the heading itself)
            section_blocks = all_blocks[section_pos + 1:next_section_pos]
            section_block_count = len(section_blocks)
        
            # Check for gray callout if section has >5 blocks
            if section_block_count > 5:
                found_callout = False
                for block in section_blocks[:3]:  # Check first few blocks
                    if block.get("type") == "callout":
                        bg_color = block.get("properties", {}).get("backgroundColor", "")
                        content = str(block.get("content", "") or block.get("text", ""))
                        if "gray" in bg_color.lower() and "Section length:" in content:
                            found_callout = True
                            break
            
                if not found_callout:
                    errors.append(f"[X] Section '{section_name}' has {section_block_count} blocks (>5) but missing gray callout with section length")
                else:
                    checks_passed.append(f"[C] Section '{section_name}' has {section_block_count} blocks (>5) but has gray callout with section length")
        
            # Check for development notice if section has <3 blocks
            if section_block_count < 3:
                found_notice = False
                for block in section_blocks:
                    if block.get("type") == "paragraph":
                        content = str(block.get("content", "") or block.get("text", ""))
                        if "under development" in content.lower():
                            found_notice = True
                            break
            
                if not found_notice:
                    errors.append(f"[X] Section '{section_name}' has {section_block_count} blocks (<3) but missing development notice paragraph")
                else:
                    checks_passed.append(f"[C] Section '{section_name}' has {section_block_count} blocks (<3) but has development notice paragraph")
    
        # Check for Revision History at end
        has_revision = False
        for idx, name in heading2_sections:
            if "Revision History" in name and "🔄" in name:
                has_revision = True
                break
    
        if not has_revision:
            errors.append("[X] '🔄 Revision History' heading not found at end")
        else:
            checks_passed.append("[C] '🔄 Revision History' heading found at end")
    
        # Check for quarterly review todos in Revision History
        quarterly_todos = [b for b in all_blocks if b.get("type") == "todo" and any(q in str(b.get("content", "") or b.get("text", "")) for q in ["Q1 2024", "Q2 2024", "Q3 2024", "Q4 2024"])]
    
        if len(quarterly_todos) < 4:
            errors.append(f"[X] Expected 4 quarterly review todos, found {len(quarterly_todos)}")
        else:
            checks_passed.append(f"[C] Found 4 quarterly review todos as expected")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

    # -----------------------------------------------------------------------------
    # add-onboarding-progress-tracking-v2
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_add_onboarding_progress_tracking(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Task: Add progress tracking to Onboarding Guide.
    
    Validates:
    1. Green callout with 📈 icon after First Day Tasks heading
    2. Divider before First Week Goals section
    3. Progress Checkpoint heading before First Week Goals
    4. Paragraph with task count after Progress Checkpoint
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    # Find Onboarding Guide page
    try:
        page_results = final_state_backend.query({
            "collection": "pages",
            "filter": {"title": "Onboarding Guide"}
        })
    
        if not page_results:
            errors.append("[X] Onboarding Guide page not found")
        else:
            checks_passed.append("[C] Onboarding Guide page found")
    
        page = page_results[0]
        # Query blocks collection for this page
        all_blocks = final_state_backend.query({
            "collection": "blocks",
            "filter": {"pageId": page.get("_id")}
        })
    
        # Find First Day Tasks and First Week Goals headings
        first_day_idx = None
        first_week_idx = None
    
        for i, block in enumerate(all_blocks):
            if block.get("type") in ["heading2", "heading_2"]:
                content = str(block.get("content", "") or block.get("text", ""))
                if "First Day Tasks" in content:
                    first_day_idx = i
                elif "First Week Goals" in content:
                    first_week_idx = i
    
        if first_day_idx is None or first_week_idx is None:
            errors.append("[X] First Day Tasks or First Week Goals headings not found")
        else:
            checks_passed.append("[C] First Day Tasks or First Week Goals headings found")
    
        # Check for green callout after First Day Tasks heading
        has_green_callout = False
        for i in range(first_day_idx + 1, min(first_day_idx + 3, len(all_blocks))):
            if all_blocks[i].get("type") == "callout":
                bg = all_blocks[i].get("properties", {}).get("backgroundColor", "")
                icon = all_blocks[i].get("properties", {}).get("icon", "")
                content = str(all_blocks[i].get("content", "") or all_blocks[i].get("text", ""))
                if "green" in bg.lower() and "📈" in (icon or content) and "First Day Checklist" in content:
                    has_green_callout = True
                    break
    
        if not has_green_callout:
            errors.append("[X] Green callout with 📈 icon after First Day Tasks not found")
        else:
            checks_passed.append("[C] Green callout with 📈 icon after First Day Tasks found")
    
        # Check for divider before First Week Goals
        has_divider = False
        for i in range(max(0, first_week_idx - 5), first_week_idx):
            if all_blocks[i].get("type") == "divider":
                has_divider = True
                break
    
        if not has_divider:
            errors.append("[X] Divider not found before First Week Goals section")
        else:
            checks_passed.append("[C] Divider found before First Week Goals section")
    
        # Check for Progress Checkpoint before First Week Goals
        has_checkpoint = False
        checkpoint_idx = None
        for i in range(max(0, first_week_idx - 5), first_week_idx):
            if all_blocks[i].get("type") in ["heading3", "heading_3"]:
                content = str(all_blocks[i].get("content", "") or all_blocks[i].get("text", ""))
                if "Progress Checkpoint" in content and "🔄" in content:
                    has_checkpoint = True
                    checkpoint_idx = i
                    break
    
        if not has_checkpoint:
            errors.append("[X] '🔄 Progress Checkpoint' heading not found before First Week Goals")
        else:
            checks_passed.append("[C] '🔄 Progress Checkpoint' heading found before First Week Goals")
    
        # Check for paragraph after Progress Checkpoint with task count
        has_paragraph = False
        if checkpoint_idx is not None:
            for i in range(checkpoint_idx + 1, min(checkpoint_idx + 3, len(all_blocks))):
                if all_blocks[i].get("type") == "paragraph":
                    content = str(all_blocks[i].get("content", "") or all_blocks[i].get("text", ""))
                    if "Day 1" in content and "tasks" in content.lower():
                        has_paragraph = True
                        break
    
        if not has_paragraph:
            errors.append("[X] Paragraph with task count not found after Progress Checkpoint")
        else:
            checks_passed.append("[C] Paragraph with task count found after Progress Checkpoint")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

    # -----------------------------------------------------------------------------
    # create-project-status-report-v2
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_create_project_status_report(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Task: Create Project Status Report under Project Roadmap.
    
    Validates:
    1. 'Project Status Report' page exists under Project Roadmap
    2. Proper heading structure
    3. Analysis of Q1 and Q2 Goals with block counts
    4. Blue callouts with metrics
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    # Find Project Roadmap page
    try:
        roadmap_results = final_state_backend.query({
            "collection": "pages",
            "filter": {"title": "Project Roadmap"}
        })
    
        if not roadmap_results:
            errors.append("[X] Project Roadmap page not found")
        else:
            checks_passed.append("[C] Project Roadmap page found")
    
        roadmap_id = roadmap_results[0].get("_id")
    
        # Find Project Status Report page
        report_results = final_state_backend.query({
            "collection": "pages",
            "filter": {"title": "Project Status Report"}
        })
    
        if not report_results:
            errors.append("[X] 'Project Status Report' page not found")
        else:
            checks_passed.append("[C] 'Project Status Report' page found")
    
        report_page = report_results[0]
    
        # Verify it's under Project Roadmap
        if report_page.get("parentId") != roadmap_id:
            errors.append("[X] Project Status Report is not a child of Project Roadmap")
        else:
            checks_passed.append("[C] Project Status Report is a child of Project Roadmap")
    
        # Query blocks collection for this page
        all_blocks = final_state_backend.query({
            "collection": "blocks",
            "filter": {"pageId": report_page.get("_id")}
        })
    
        # Check for main heading
        has_main_heading = False
        for block in all_blocks:
            if block.get("type") in ["heading1", "heading_1"]:
                content = str(block.get("content", "") or block.get("text", ""))
                if "Quarterly Project Status" in content and "📊" in content:
                    has_main_heading = True
                    break
    
        if not has_main_heading:
            errors.append("[X] '📊 Quarterly Project Status' heading not found")
        else:
            checks_passed.append("[C] '📊 Quarterly Project Status' heading found")
    
        # Check for Goals Overview heading
        has_overview = False
        for block in all_blocks:
            if block.get("type") in ["heading2", "heading_2"]:
                content = str(block.get("content", "") or block.get("text", ""))
                if "Goals Overview" in content and "🎯" in content:
                    has_overview = True
                    break
    
        if not has_overview:
            errors.append("[X] '🎯 Goals Overview' heading not found")
        else:
            checks_passed.append("[C] '🎯 Goals Overview' heading found")
    
        # Check for Q1 and Q2 headings
        quarter_headings = [b for b in all_blocks if b.get("type") in ["heading3", "heading_3"] and any(q in str(b.get("content", "") or b.get("text", "")) for q in ["Q1 Goals", "Q2 Goals"])]
    
        if len(quarter_headings) < 2:
            errors.append(f"[X] Expected headings for Q1 and Q2 Goals, found {len(quarter_headings)}")
        else:
            checks_passed.append(f"[C] Expected headings for Q1 and Q2 Goals, found {len(quarter_headings)}")
    
        # Check for blue callouts with block counts
        callouts_with_metrics = [b for b in all_blocks if b.get("type") == "callout" and "Block count:" in str(b.get("content", "") or b.get("text", ""))]
    
        if len(callouts_with_metrics) < 2:
            errors.append(f"[X] Expected 2 callouts with block counts, found {len(callouts_with_metrics)}")
        else:
            checks_passed.append(f"[C] Found 2 callouts with block counts as expected")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

    # -----------------------------------------------------------------------------
    # add-api-documentation-footer-v2
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_add_api_documentation_footer(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Task: Add comprehensive footer to API Documentation.
    
    Validates:
    1. Divider and Additional Resources heading at end
    2. Blue callout with three bookmarks
    3. Paragraph with section count and contact info
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    # Find API Documentation page
    try:
        page_results = final_state_backend.query({
            "collection": "pages",
            "filter": {"title": "API Documentation"}
        })
    
        if not page_results:
            errors.append("[X] API Documentation page not found")
        else:
            checks_passed.append("[C] API Documentation page found")
    
        page = page_results[0]
        # Query blocks collection for this page
        all_blocks = final_state_backend.query({
            "collection": "blocks",
            "filter": {"pageId": page.get("_id")}
        })
    
        # Check for Additional Resources heading
        has_resources_heading = False
        for block in all_blocks:
            if block.get("type") in ["heading2", "heading_2"]:
                content = str(block.get("content", "") or block.get("text", ""))
                if "Additional Resources" in content and "📚" in content:
                    has_resources_heading = True
                    break
    
        if not has_resources_heading:
            errors.append("[X] '📚 Additional Resources' heading not found")
        else:
            checks_passed.append("[C] '📚 Additional Resources' heading found")
    
        # Check for blue callout with bookmarks
        has_blue_callout = False
        for block in all_blocks:
            if block.get("type") == "callout":
                bg = block.get("properties", {}).get("backgroundColor", "")
                icon = block.get("properties", {}).get("icon", "")
                if "blue" in bg.lower() and "🔗" in (icon or str(block.get("content", "") or block.get("text", ""))):
                    has_blue_callout = True
                    break
    
        if not has_blue_callout:
            errors.append("[X] Blue callout with 🔗 icon not found")
        else:
            checks_passed.append("[C] Blue callout with 🔗 icon found")
    
        # Check for bookmarks
        bookmarks = [b for b in all_blocks if b.get("type") == "bookmark"]
        footer_bookmarks = [b for b in bookmarks if any(url in str(b.get("properties", {}).get("url", "")) for url in ["swagger", "github", "status"])]
    
        if len(footer_bookmarks) < 3:
            errors.append(f"[X] Expected 3 bookmark blocks with specific URLs, found {len(footer_bookmarks)}")
        else:
            checks_passed.append(f"[C] Found 3 bookmark blocks with specific URLs as expected")
    
        # Check for paragraph with section count
        has_summary_paragraph = False
        for block in all_blocks:
            if block.get("type") == "paragraph":
                content = str(block.get("content", "") or block.get("text", ""))
                if "documentation contains" in content.lower() and "api-support@example.com" in content:
                    has_summary_paragraph = True
                    break
    
        if not has_summary_paragraph:
            errors.append("[X] Summary paragraph with section count and contact info not found")
        else:
            checks_passed.append("[C] Summary paragraph with section count and contact info found")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

    # -----------------------------------------------------------------------------
    # reorganize-external-resources-by-domain-v2
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_reorganize_external_resources_by_domain(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Task: Reorganize External Resources page by domain.
    
    Validates:
    1. Statistics callout at top with accurate counts
    2. Bookmarks grouped by domain with heading3 labels
    3. Dividers between domain groups
    4. New bookmark at end
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    # Find External Resources & Links page
    try:
        page_results = final_state_backend.query({
            "collection": "pages",
            "filter": {"title": "External Resources & Links"}
        })
    
        if not page_results:
            # Try alternate title
            page_results = final_state_backend.query({
                "collection": "pages",
                "filter": {"title": "External Resources and Links"}
            })
    
        if not page_results:
            errors.append("[X] External Resources & Links page not found")
        else:
            checks_passed.append("[C] External Resources & Links page found")
    
        page = page_results[0]
        # Query blocks collection for this page
        all_blocks = final_state_backend.query({
            "collection": "blocks",
            "filter": {"pageId": page.get("_id")}
        })
    
        # Check for statistics callout at top
        has_stats_callout = False
        for i in range(min(10, len(all_blocks))):
            if all_blocks[i].get("type") == "callout":
                bg = all_blocks[i].get("properties", {}).get("backgroundColor", "")
                icon = all_blocks[i].get("properties", {}).get("icon", "")
                content = str(all_blocks[i].get("content", "") or all_blocks[i].get("text", ""))
                if "blue" in bg.lower() and "📊" in (icon or content) and "Resource Statistics" in content:
                    has_stats_callout = True
                    break
    
        if not has_stats_callout:
            errors.append("[X] Statistics callout with 📊 icon not found at top")
        else:
            checks_passed.append("[C] Statistics callout with 📊 icon found at top")
    
        # Check for domain headings
        domain_headings = [b for b in all_blocks if b.get("type") in ["heading3", "heading_3"] and any(d in str(b.get("content", "") or b.get("text", "")) for d in ["github.com", "typescriptlang.org", "developer.mozilla.org"])]
    
        if len(domain_headings) < 1:
            errors.append("[X] No domain-specific headings found")
        else:
            checks_passed.append("[C] domain-specific headings found")
    
        # Check for new bookmark at end
        has_awesome_bookmark = False
        bookmarks = [b for b in all_blocks if b.get("type") == "bookmark"]
        for bookmark in bookmarks:
            url = bookmark.get("properties", {}).get("url", "")
            if "awesome.acmecorp.com" in url:
                has_awesome_bookmark = True
                break
    
        if not has_awesome_bookmark:
            errors.append("[X] New bookmark to awesome.acmecorp.com not found")
        else:
            checks_passed.append("[C] New bookmark to awesome.acmecorp.com found")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

    # -----------------------------------------------------------------------------
    # add-prd-technical-architecture-v2
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_add_prd_technical_architecture(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Task: Add Technical Architecture section to PRD.
    
    Validates:
    1. '📐 Technical Architecture' heading3 between Part 2 and Part 3
    2. Two specific paragraphs about architecture
    3. YAML code block with services configuration
    4. Three architecture bullet points
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    # Find Comprehensive Product Requirements Document page
    try:
        page_results = final_state_backend.query({
            "collection": "pages",
            "filter": {"title": "Comprehensive Product Requirements Document"}
        })
    
        if not page_results:
            errors.append("[X] Comprehensive Product Requirements Document page not found")
        else:
            checks_passed.append("[C] Comprehensive Product Requirements Document page found")
    
        page = page_results[0]
        # Query blocks collection for this page
        all_blocks = final_state_backend.query({
            "collection": "blocks",
            "filter": {"pageId": page.get("_id")}
        })
    
        # Find Overview sections
        part2_idx = None
        part3_idx = None
        tech_arch_idx = None
    
        for i, block in enumerate(all_blocks):
            if block.get("type") in ["heading3", "heading_3"]:
                content = str(block.get("content", "") or block.get("text", ""))
                if "Overview - Part 2" in content:
                    part2_idx = i
                elif "Overview - Part 3" in content:
                    part3_idx = i
                elif "Technical Architecture" in content and "📐" in content:
                    tech_arch_idx = i
    
        if part2_idx is None or part3_idx is None:
            errors.append("[X] Overview Part 2 or Part 3 headings not found")
        else:
            checks_passed.append("[C] Overview Part 2 or Part 3 headings found")
    
        if tech_arch_idx is None:
            errors.append("[X] '📐 Technical Architecture' heading not found")
        else:
            checks_passed.append("[C] '📐 Technical Architecture' heading found")
    
        # Verify positioning
        if not (part2_idx < tech_arch_idx < part3_idx):
            errors.append("[X] Technical Architecture not positioned between Part 2 and Part 3")
        else:
            checks_passed.append("[C] Technical Architecture positioned between Part 2 and Part 3")
    
        # Check for two paragraphs about architecture
        arch_paragraphs = 0
        for i in range(tech_arch_idx + 1, min(tech_arch_idx + 5, len(all_blocks))):
            if all_blocks[i].get("type") == "paragraph":
                content = str(all_blocks[i].get("content", "") or all_blocks[i].get("text", ""))
                if "microservices" in content.lower() or "message queue" in content.lower():
                    arch_paragraphs += 1
    
        if arch_paragraphs < 2:
            errors.append(f"[X] Expected 2 architecture paragraphs, found {arch_paragraphs}")
        else:
            checks_passed.append(f"[C] Found 2 architecture paragraphs as expected")
    
        # Check for YAML code block
        has_yaml_code = False
        for i in range(tech_arch_idx + 1, min(tech_arch_idx + 8, len(all_blocks))):
            if all_blocks[i].get("type") == "code":
                lang = all_blocks[i].get("properties", {}).get("language", "")
                content = str(all_blocks[i].get("content", "") or all_blocks[i].get("text", ""))
                if "yaml" in lang.lower() and "services:" in content and "api:" in content:
                    has_yaml_code = True
                    break
    
        if not has_yaml_code:
            errors.append("[X] YAML code block with services configuration not found")
        else:
            checks_passed.append("[C] YAML code block with services configuration found")
    
        # Check for three architecture bullets
        arch_bullets = 0
        for i in range(tech_arch_idx + 1, min(tech_arch_idx + 12, len(all_blocks))):
            if all_blocks[i].get("type") == "bulletedList":
                content = str(all_blocks[i].get("content", "") or all_blocks[i].get("text", ""))
                if any(term in content for term in ["RESTful", "Redis", "PostgreSQL"]):
                    arch_bullets += 1
    
        if arch_bullets < 3:
            errors.append(f"[X] Expected 3 architecture bullet points, found {arch_bullets}")
        else:
            checks_passed.append(f"[C] Found 3 architecture bullet points as expected")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

    # -----------------------------------------------------------------------------
    # add-bug-tracker-security-section-v2
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_add_bug_tracker_security_section(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Task: Add Urgent Security Issues section to Bug Tracker.
    
    Validates:
    1. '🔐 Urgent - Security Issues' heading between Critical and Medium
    2. Three security-related unchecked todos
    3. Red callout with shield icon
    4. Summary paragraph with accurate bug counts
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    # Find Bug Tracker page
    try:
        page_results = final_state_backend.query({
            "collection": "pages",
            "filter": {"title": "Bug Tracker"}
        })
    
        if not page_results:
            errors.append("[X] Bug Tracker page not found")
        else:
            checks_passed.append("[C] Bug Tracker page found")
    
        page = page_results[0]
        # Query blocks collection for this page
        all_blocks = final_state_backend.query({
            "collection": "blocks",
            "filter": {"pageId": page.get("_id")}
        })
    
        # Find section headings
        critical_idx = None
        medium_idx = None
        security_idx = None
    
        for i, block in enumerate(all_blocks):
            if block.get("type") in ["heading2", "heading_2"]:
                content = str(block.get("content", "") or block.get("text", ""))
                if "Critical Bugs" in content or "Critical" in content:
                    critical_idx = i
                elif "Medium Priority" in content:
                    medium_idx = i
                elif "Urgent - Security Issues" in content and "🔐" in content:
                    security_idx = i
    
        if critical_idx is None or medium_idx is None:
            errors.append("[X] Critical Bugs or Medium Priority headings not found")
        else:
            checks_passed.append("[C] Critical Bugs or Medium Priority headings found")
    
        if security_idx is None:
            errors.append("[X] '🔐 Urgent - Security Issues' heading not found")
        else:
            checks_passed.append("[C] '🔐 Urgent - Security Issues' heading found")
    
        # Verify positioning
        if not (critical_idx < security_idx < medium_idx):
            errors.append("[X] Security Issues section not positioned between Critical and Medium")
        else:
            checks_passed.append("[C] Security Issues section positioned between Critical and Medium")
    
        # Check for three security todos
        expected_todos = [
            "SQL injection vulnerability in user search",
            "XSS issue in comment rendering",
            "authentication tokens to prevent session hijacking"
        ]
    
        found_todos = 0
        for i in range(security_idx + 1, min(security_idx + 6, len(all_blocks))):
            if all_blocks[i].get("type") == "todo":
                content = str(all_blocks[i].get("content", "") or all_blocks[i].get("text", ""))
                is_checked = all_blocks[i].get("properties", {}).get("checked", True)
                if not is_checked and any(expected in content for expected in expected_todos):
                    found_todos += 1
    
        if found_todos < 3:
            errors.append(f"[X] Expected 3 security todos, found {found_todos}")
        else:
            checks_passed.append(f"[C] Found 3 security todos as expected")
    
        # Check for red callout with shield
        has_red_callout = False
        for i in range(security_idx + 1, min(security_idx + 8, len(all_blocks))):
            if all_blocks[i].get("type") == "callout":
                bg = all_blocks[i].get("properties", {}).get("backgroundColor", "")
                icon = all_blocks[i].get("properties", {}).get("icon", "")
                content = str(all_blocks[i].get("content", "") or all_blocks[i].get("text", ""))
                if "red" in bg.lower() and "🛡" in (icon or content) and "24 hours" in content:
                    has_red_callout = True
                    break
    
        if not has_red_callout:
            errors.append("[X] Red callout with 🛡️ icon and deployment timeline not found")
        else:
            checks_passed.append("[C] Red callout with 🛡️ icon and deployment timeline found")
    
        # Check for summary paragraph with bug counts
        has_summary = False
        for block in all_blocks:
            if block.get("type") == "paragraph":
                content = str(block.get("content", "") or block.get("text", ""))
                if "Total bugs tracked:" in content and "Urgent Security: 3" in content:
                    has_summary = True
                    break
    
        if not has_summary:
            errors.append("[X] Summary paragraph with bug counts not found")
        else:
            checks_passed.append("[C] Summary paragraph with bug counts found")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

    # -----------------------------------------------------------------------------
    # add-prd-table-of-contents-v2
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_add_prd_table_of_contents(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Task: Add table of contents section analyzing heading_2 and heading_3 blocks.
    
    Validates:
    1. TOC heading_2 appears at beginning after title
    2. All heading_2 blocks listed as numbered items
    3. heading_3 blocks as bulleted sub-items under parent heading_2
    4. Divider separates TOC from content
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    # Find PRD page
    try:
        page_results = final_state_backend.query({
            "collection": "pages",
            "filter": {"title": "Comprehensive Product Requirements Document"}
        })
    
        if not page_results:
            errors.append("[X] Comprehensive Product Requirements Document page not found")
        else:
            checks_passed.append("[C] Comprehensive Product Requirements Document page found")
    
        page = page_results[0]
        # Query blocks collection for this page
        all_blocks = final_state_backend.query({
            "collection": "blocks",
            "filter": {"pageId": page.get("_id")}
        })
    
        if not all_blocks:
            errors.append("[X] Page has no content blocks")
        else:
            checks_passed.append("[C] Page has content blocks")
    
        # Find TOC heading
        toc_idx = None
        for i, block in enumerate(all_blocks):
            if block.get("type") in ["heading2", "heading_2"]:
                content = str(block.get("content", "") or block.get("text", ""))
                if "Table of Contents" in content and "📑" in content:
                    toc_idx = i
                    break
    
        if toc_idx is None:
            errors.append("[X] Table of Contents heading_2 not found")
        else:
            checks_passed.append("[C] Table of Contents heading_2 found")
    
        # TOC should be near the beginning (within first 3 blocks)
        if toc_idx > 2:
            errors.append(f"[X] Table of Contents should be at beginning, found at index {toc_idx}")
        else:
            checks_passed.append(f"[C] Table of Contents should be at beginning, found at index {toc_idx}")
    
        # Check for divider after TOC section
        divider_found = False
        for i in range(toc_idx + 1, min(toc_idx + 30, len(all_blocks))):
            if all_blocks[i].get("type") == "divider":
                divider_found = True
                break
    
        if not divider_found:
            errors.append("[X] Divider not found after Table of Contents")
        else:
            checks_passed.append("[C] Divider found after Table of Contents")
    
        # Count actual heading_2 and heading_3 blocks (excluding TOC itself)
        h2_count = 0
        h3_count = 0
        for i, block in enumerate(all_blocks):
            if i == toc_idx:
                continue
            if block.get("type") in ["heading2", "heading_2"]:
                h2_count += 1
            elif block.get("type") in ["heading3", "heading_3"]:
                h3_count += 1
    
        # Check for numbered and bulleted lists in TOC section
        has_numbered = False
        has_bulleted = False
        for i in range(toc_idx + 1, min(toc_idx + 30, len(all_blocks))):
            block = all_blocks[i]
            if block.get("type") == "divider":
                break
            if block.get("type") == "numberedList":
                has_numbered = True
            elif block.get("type") == "bulletedList":
                has_bulleted = True
    
        if not has_numbered:
            errors.append("[X] TOC should contain numbered list items for heading_2 blocks")
        else:
            checks_passed.append("[C] TOC should contain numbered list items for heading_2 blocks")
    
        if h3_count > 0 and not has_bulleted:
            errors.append("[X] TOC should contain bulleted sub-items for heading_3 blocks")
        else:
            checks_passed.append("[C] TOC should contain bulleted sub-items for heading_3 blocks")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

    # -----------------------------------------------------------------------------
    # add-engineering-wiki-documentation-index-v2
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_add_engineering_wiki_documentation_index(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Task: Add documentation index section with child page and reorganize content.
    
    Validates:
    1. Documentation Structure heading_2 in correct position
    2. API Reference Guide child page exists with plug icon
    3. Purple callout with book icon
    4. Three heading_3 sections
    5. Bookmark to API Reference Guide
    6. Development Setup section moved
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    # Find Engineering Wiki page
    try:
        wiki_results = final_state_backend.query({
            "collection": "pages",
            "filter": {"title": "Engineering Wiki"}
        })
    
        if not wiki_results:
            errors.append("[X] Engineering Wiki page not found")
        else:
            checks_passed.append("[C] Engineering Wiki page found")
    
        wiki = wiki_results[0]
        wiki_id = wiki.get("_id")
        # Query blocks collection for this page
        all_blocks = final_state_backend.query({
            "collection": "blocks",
            "filter": {"pageId": wiki_id}
        })
    
        # Find Documentation Structure heading
        doc_structure_idx = None
        for i, block in enumerate(all_blocks):
            if block.get("type") in ["heading2", "heading_2"]:
                content = str(block.get("content", "") or block.get("text", ""))
                if "Documentation Structure" in content and "📚" in content:
                    doc_structure_idx = i
                    break
    
        if doc_structure_idx is None:
            errors.append("[X] '📚 Documentation Structure' heading not found")
        else:
            checks_passed.append("[C] '📚 Documentation Structure' heading found")
    
        # Check for API Reference Guide child page
        api_guide_results = final_state_backend.query({
            "collection": "pages",
            "filter": {"title": "API Reference Guide", "parentId": wiki_id}
        })
    
        if not api_guide_results:
            errors.append("[X] API Reference Guide child page not found")
        else:
            checks_passed.append("[C] API Reference Guide child page found")
    
        api_guide = api_guide_results[0]
        if api_guide.get("icon") != "🔌":
            errors.append("[X] API Reference Guide should have plug icon 🔌")
        else:
            checks_passed.append("[C] API Reference Guide should have plug icon 🔌")
    
        # Look for purple callout after Documentation Structure
        callout_found = False
        for i in range(doc_structure_idx + 1, min(doc_structure_idx + 5, len(all_blocks))):
            block = all_blocks[i]
            if block.get("type") == "callout":
                properties = block.get("properties", {})
                bg_color = properties.get("backgroundColor", "")
                icon = properties.get("icon", "")
                content = str(block.get("content", "") or block.get("text", ""))
                if "purple" in bg_color and "📖" in icon and "technical documentation" in content.lower():
                    callout_found = True
                    break
    
        if not callout_found:
            errors.append("[X] Purple callout with 📖 icon not found")
        else:
            checks_passed.append("[C] Purple callout with 📖 icon found")
    
        # Check for three heading_3 sections (search after Documentation Structure)
        # Note: Development Setup section is moved between Architecture Docs and Setup Guides
        h3_sections = []
        for i in range(doc_structure_idx + 1, len(all_blocks)):
            block = all_blocks[i]
            if block.get("type") in ["heading3", "heading_3"]:
                content = str(block.get("content", "") or block.get("text", ""))
                h3_sections.append(content)
    
        required_h3 = ["Architecture Docs", "Setup Guides", "API Documentation"]
        for required in required_h3:
            found = any(required in section for section in h3_sections)
            if not found:
                errors.append(f"[X] Missing heading_3: {required}")
            else:
                checks_passed.append(f"[C] has heading_3: {required}")
    
        # Check for bookmark
        bookmark_found = False
        for block in all_blocks:
            if block.get("type") == "bookmark":
                properties = block.get("properties", {})
                caption = str(properties.get("caption", ""))
                if "API Reference Guide" in caption:
                    bookmark_found = True
                    break
    
        if not bookmark_found:
            errors.append("[X] Bookmark to API Reference Guide not found")
        else:
            checks_passed.append("[C] Bookmark to API Reference Guide found")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

    # -----------------------------------------------------------------------------
    # add-weekly-standup-team-collaboration-v2
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_add_weekly_standup_team_collaboration(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Task: Insert Team Collaboration Updates section with todos.
    
    Validates:
    1. Team Collaboration Updates heading_2 in correct position
    2. Three unchecked todos with exact text
    3. Divider after todos
    4. Original Blockers section intact
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    # Find Weekly Standup Template page
    try:
        page_results = final_state_backend.query({
            "collection": "pages",
            "filter": {"title": "Weekly Standup Template"}
        })
    
        if not page_results:
            errors.append("[X] Weekly Standup Template page not found")
        else:
            checks_passed.append("[C] Weekly Standup Template page found")
    
        page = page_results[0]
        # Query blocks collection for this page
        all_blocks = final_state_backend.query({
            "collection": "blocks",
            "filter": {"pageId": page.get("_id")}
        })
    
        # Find Team Collaboration Updates heading
        collab_idx = None
        blockers_idx = None
    
        for i, block in enumerate(all_blocks):
            if block.get("type") in ["heading2", "heading_2"]:
                content = str(block.get("content", "") or block.get("text", ""))
                if "Team Collaboration Updates" in content and "📊" in content:
                    collab_idx = i
                elif "Blockers" in content:
                    blockers_idx = i
    
        if collab_idx is None:
            errors.append("[X] '📊 Team Collaboration Updates' heading not found")
        else:
            checks_passed.append("[C] '📊 Team Collaboration Updates' heading found")
    
        if blockers_idx is None:
            errors.append("[X] Blockers heading not found")
        else:
            checks_passed.append("[C] Blockers heading found")
    
        # Verify Team Collaboration comes before Blockers
        if collab_idx >= blockers_idx:
            errors.append("[X] Team Collaboration Updates should appear before Blockers")
        else:
            checks_passed.append("[C] Team Collaboration Updates should appear before Blockers")
    
        # Check for three todos with exact text
        required_todos = [
            "Pair programming session with junior developer",
            "Code review for authentication module",
            "Knowledge sharing on new deployment process"
        ]
    
        found_todos = []
        for i in range(collab_idx + 1, blockers_idx):
            block = all_blocks[i]
            if block.get("type") == "todo":
                content = str(block.get("content", "") or block.get("text", ""))
                if block.get("properties", {}).get("checked") == False:
                    for req in required_todos:
                        if req in content:
                            found_todos.append(req)
    
        if len(found_todos) < 3:
            errors.append(f"[X] Found {len(found_todos)} of 3 required todos")
        else:
            checks_passed.append(f"[C] Found {len(found_todos)} of 3 required todos")
    
        # Check for divider
        divider_found = False
        for i in range(collab_idx + 1, blockers_idx):
            if all_blocks[i].get("type") == "divider":
                divider_found = True
                break
    
        if not divider_found:
            errors.append("[X] Divider not found after Team Collaboration Updates")
        else:
            checks_passed.append("[C] Divider found after Team Collaboration Updates")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

    # -----------------------------------------------------------------------------
    # create-design-system-audit-page-v2
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_create_design_system_audit_page(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Task: Create Design System Audit child page analyzing parent structure.
    
    Validates:
    1. Page created as child of Design System
    2. Today's date in audit paragraph
    3. Numbered list with parent heading_2 sections
    4. Blue callout with recommendations
    5. Three unchecked todos
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    # Find Design System page
    try:
        design_results = final_state_backend.query({
            "collection": "pages",
            "filter": {"title": "Design System"}
        })
    
        if not design_results:
            errors.append("[X] Design System page not found")
        else:
            checks_passed.append("[C] Design System page found")
    
        design_system = design_results[0]
        design_id = design_system.get("_id")
    
        # Find Design System Audit child page
        audit_results = final_state_backend.query({
            "collection": "pages",
            "filter": {"title": "Design System Audit", "parentId": design_id}
        })
    
        if not audit_results:
            errors.append("[X] Design System Audit page not found as child of Design System")
        else:
            checks_passed.append("[C] Design System Audit page found as child of Design System")
    
        audit_page = audit_results[0]
        # Query blocks collection for this page
        all_blocks = final_state_backend.query({
            "collection": "blocks",
            "filter": {"pageId": audit_page.get("_id")}
        })
    
        # Check for heading_1
        if not all_blocks or all_blocks[0].get("type") not in ["heading1", "heading_1"]:
            errors.append("[X] Page should start with heading_1")
        else:
            checks_passed.append("[C] Page should start with heading_1")
    
        # Check for Component Inventory heading_2
        inventory_found = False
        for block in all_blocks:
            if block.get("type") in ["heading2", "heading_2"]:
                content = str(block.get("content", "") or block.get("text", ""))
                if "Component Inventory" in content and "📋" in content:
                    inventory_found = True
                    break
    
        if not inventory_found:
            errors.append("[X] '📋 Component Inventory' heading not found")
        else:
            checks_passed.append("[C] '📋 Component Inventory' heading found")
    
        # Check for audit date paragraph
        date_found = False
        for block in all_blocks:
            if block.get("type") == "paragraph":
                content = str(block.get("content", "") or block.get("text", ""))
                if "Audit date:" in content:
                    date_found = True
                    break
    
        if not date_found:
            errors.append("[X] Audit date paragraph not found")
        else:
            checks_passed.append("[C] Audit date paragraph found")
    
        # Check for numbered list
        has_numbered = any(block.get("type") == "numberedList" for block in all_blocks)
        if not has_numbered:
            errors.append("[X] Numbered list not found")
        else:
            checks_passed.append("[C] Numbered list found")
    
        # Check for Recommendations heading with blue callout
        recommendations_found = False
        callout_found = False
        for i, block in enumerate(all_blocks):
            if block.get("type") in ["heading2", "heading_2"]:
                content = str(block.get("content", "") or block.get("text", ""))
                if "Recommendations" in content and "🔍" in content:
                    recommendations_found = True
                    # Look for blue callout nearby
                    for j in range(i + 1, min(i + 5, len(all_blocks))):
                        if all_blocks[j].get("type") == "callout":
                            bg = all_blocks[j].get("properties", {}).get("backgroundColor", "")
                            if "blue" in bg:
                                callout_found = True
                    break
    
        if not recommendations_found:
            errors.append("[X] '🔍 Recommendations' heading not found")
        else:
            checks_passed.append("[C] '🔍 Recommendations' heading found")
    
        if not callout_found:
            errors.append("[X] Blue callout with recommendations not found")
        else:
            checks_passed.append("[C] Blue callout with recommendations found")
    
        # Check for three unchecked todos
        unchecked_todos = [b for b in all_blocks if b.get("type") == "todo" and not b.get("properties", {}).get("checked")]
        if len(unchecked_todos) < 3:
            errors.append(f"[X] Found {len(unchecked_todos)} unchecked todos, expected at least 3")
        else:
            checks_passed.append(f"[C] Found {len(unchecked_todos)} unchecked todos, expected at least 3")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

    # -----------------------------------------------------------------------------
    # add-design-system-style-guide-v2
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_add_design_system_style_guide(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Task: Add Component Style Guide section with spacing system.
    
    Validates:
    1. Divider and heading_2 at end of page
    2. Spacing System heading_3 with CSS code block
    3. Five bulleted list items for spacing
    4. Usage Guidelines heading_3 with blue callout
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    # Find Design System page
    try:
        page_results = final_state_backend.query({
            "collection": "pages",
            "filter": {"title": "Design System"}
        })
    
        if not page_results:
            errors.append("[X] Design System page not found")
        else:
            checks_passed.append("[C] Design System page found")
    
        page = page_results[0]
        # Query blocks collection for this page
        all_blocks = final_state_backend.query({
            "collection": "blocks",
            "filter": {"pageId": page.get("_id")}
        })
    
        # Find Component Style Guide heading (should be near end)
        style_guide_idx = None
        for i, block in enumerate(all_blocks):
            if block.get("type") in ["heading2", "heading_2"]:
                content = str(block.get("content", "") or block.get("text", ""))
                if "Component Style Guide" in content and "🎨" in content:
                    style_guide_idx = i
                    break
    
        if style_guide_idx is None:
            errors.append("[X] '🎨 Component Style Guide' heading not found")
        else:
            checks_passed.append("[C] '🎨 Component Style Guide' heading found")
    
        # Check for divider before this section
        divider_before = False
        if style_guide_idx > 0:
            for i in range(max(0, style_guide_idx - 3), style_guide_idx):
                if all_blocks[i].get("type") == "divider":
                    divider_before = True
                    break
    
        if not divider_before:
            errors.append("[X] Divider not found before Component Style Guide")
        else:
            checks_passed.append("[C] Divider found before Component Style Guide")
    
        # Look for Spacing System heading_3
        spacing_found = False
        code_found = False
        for i in range(style_guide_idx + 1, len(all_blocks)):
            block = all_blocks[i]
            if block.get("type") in ["heading3", "heading_3"]:
                content = str(block.get("content", "") or block.get("text", ""))
                if "Spacing System" in content and "📏" in content:
                    spacing_found = True
                    # Look for code block nearby
                    for j in range(i + 1, min(i + 5, len(all_blocks))):
                        if all_blocks[j].get("type") == "code":
                            lang = all_blocks[j].get("properties", {}).get("language", "")
                            code_content = str(all_blocks[j].get("content", "") or all_blocks[j].get("text", ""))
                            if "css" in lang.lower() and ":root" in code_content and "--space" in code_content:
                                code_found = True
                    break
    
        if not spacing_found:
            errors.append("[X] '📏 Spacing System' heading_3 not found")
        else:
            checks_passed.append("[C] '📏 Spacing System' heading_3 found")
    
        if not code_found:
            errors.append("[X] CSS code block with spacing variables not found")
        else:
            checks_passed.append("[C] CSS code block with spacing variables found")
    
        # Check for bulleted list with spacing descriptions
        bulleted_count = 0
        for block in all_blocks[style_guide_idx:]:
            if block.get("type") == "bulletedList":
                content = str(block.get("content", "") or block.get("text", ""))
                if any(size in content for size in ["xs", "sm", "md", "lg", "xl"]):
                    bulleted_count += 1
    
        if bulleted_count < 5:
            errors.append(f"[X] Found {bulleted_count} spacing bullets, expected 5")
        else:
            checks_passed.append(f"[C] Found {bulleted_count} spacing bullets, expected 5")
    
        # Check for Usage Guidelines heading_3 with blue callout
        guidelines_found = False
        blue_callout_found = False
        for i in range(style_guide_idx + 1, len(all_blocks)):
            block = all_blocks[i]
            if block.get("type") in ["heading3", "heading_3"]:
                content = str(block.get("content", "") or block.get("text", ""))
                if "Usage Guidelines" in content and "🎯" in content:
                    guidelines_found = True
                    # Look for blue callout
                    for j in range(i + 1, min(i + 3, len(all_blocks))):
                        if all_blocks[j].get("type") == "callout":
                            bg = all_blocks[j].get("properties", {}).get("backgroundColor", "")
                            if "blue" in bg:
                                blue_callout_found = True
                    break
    
        if not guidelines_found:
            errors.append("[X] '🎯 Usage Guidelines' heading_3 not found")
        else:
            checks_passed.append("[C] '🎯 Usage Guidelines' heading_3 found")
    
        if not blue_callout_found:
            errors.append("[X] Blue callout under Usage Guidelines not found")
        else:
            checks_passed.append("[C] Blue callout under Usage Guidelines found")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

    # -----------------------------------------------------------------------------
    # add-design-system-component-status-v2
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_add_design_system_component_status(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Task: Insert Component Status section after Typography heading.
    
    Validates:
    1. Component Status heading_2 after Typography
    2. Orange callout with exact text
    3. Four todos: 2 checked, 2 unchecked with exact text
    4. Italic paragraph with audit dates
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    # Find Design System page
    try:
        page_results = final_state_backend.query({
            "collection": "pages",
            "filter": {"title": "Design System"}
        })
    
        if not page_results:
            errors.append("[X] Design System page not found")
        else:
            checks_passed.append("[C] Design System page found")
    
        page = page_results[0]
        # Query blocks collection for this page
        all_blocks = final_state_backend.query({
            "collection": "blocks",
            "filter": {"pageId": page.get("_id")}
        })
    
        # Find Typography and Component Status headings
        typography_idx = None
        component_status_idx = None
    
        for i, block in enumerate(all_blocks):
            if block.get("type") in ["heading2", "heading_2"]:
                content = str(block.get("content", "") or block.get("text", ""))
                if "Typography" in content:
                    typography_idx = i
                elif "Component Status" in content and "🧩" in content:
                    component_status_idx = i
    
        if typography_idx is None:
            errors.append("[X] Typography heading not found")
        else:
            checks_passed.append("[C] Typography heading found")
    
        if component_status_idx is None:
            errors.append("[X] '🧩 Component Status' heading not found")
        else:
            checks_passed.append("[C] '🧩 Component Status' heading found")
    
        # Component Status should come after Typography
        if component_status_idx <= typography_idx:
            errors.append("[X] Component Status should appear after Typography")
        else:
            checks_passed.append("[C] Component Status should appear after Typography")
    
        # Check for orange callout
        callout_found = False
        for i in range(component_status_idx + 1, min(component_status_idx + 5, len(all_blocks))):
            block = all_blocks[i]
            if block.get("type") == "callout":
                bg = block.get("properties", {}).get("backgroundColor", "")
                content = str(block.get("content", "") or block.get("text", ""))
                if "orange" in bg and "implementation status" in content.lower():
                    callout_found = True
                    break
    
        if not callout_found:
            errors.append("[X] Orange callout not found")
        else:
            checks_passed.append("[C] Orange callout found")
    
        # Check for todos
        required_checked = ["Button component", "Input fields"]
        required_unchecked = ["Modal dialogs", "Data tables"]
    
        found_checked = 0
        found_unchecked = 0
    
        for i in range(component_status_idx + 1, len(all_blocks)):
            block = all_blocks[i]
            if block.get("type") in ["heading2", "heading_2"]:
                break
            if block.get("type") == "todo":
                content = str(block.get("content", "") or block.get("text", ""))
                if block.get("properties", {}).get("checked") == True:
                    if any(req in content for req in required_checked):
                        found_checked += 1
                else:
                    if any(req in content for req in required_unchecked):
                        found_unchecked += 1
    
        if found_checked < 2:
            errors.append(f"[X] Found {found_checked} of 2 required checked todos")
        else:
            checks_passed.append(f"[C] Found {found_checked} of 2 required checked todos")
    
        if found_unchecked < 2:
            errors.append(f"[X] Found {found_unchecked} of 2 required unchecked todos")
        else:
            checks_passed.append(f"[C] Found {found_unchecked} of 2 required unchecked todos")
    
        # Check for paragraph with audit dates
        audit_paragraph_found = False
        for i in range(component_status_idx + 1, len(all_blocks)):
            block = all_blocks[i]
            if block.get("type") in ["heading2", "heading_2"]:
                break
            if block.get("type") == "paragraph":
                content = str(block.get("content", "") or block.get("text", ""))
                if "Last audit" in content and "Next audit" in content:
                    audit_paragraph_found = True
                    break
    
        if not audit_paragraph_found:
            errors.append("[X] Paragraph with audit dates not found")
        else:
            checks_passed.append("[C] Paragraph with audit dates found")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

    # -----------------------------------------------------------------------------
    # add-onboarding-milestones-section-v2
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_add_onboarding_milestones_section(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Task: Add Onboarding Milestones section to Onboarding Guide.
    
    Validates:
    1. Divider and Onboarding Milestones heading_2
    2. Yellow callout with star icon
    3. Week 1 Achievements heading_3 with 3 unchecked todos
    4. Month 1 Goals heading_3 with 3 unchecked todos
    5. Quote block at end
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    # Find Onboarding Guide page
    try:
        page_results = final_state_backend.query({
            "collection": "pages",
            "filter": {"title": "Onboarding Guide"}
        })
    
        if not page_results:
            errors.append("[X] Onboarding Guide page not found")
        else:
            checks_passed.append("[C] Onboarding Guide page found")
    
        page = page_results[0]
        # Query blocks collection for this page
        all_blocks = final_state_backend.query({
            "collection": "blocks",
            "filter": {"pageId": page.get("_id")}
        })
    
        # Find Onboarding Milestones heading
        milestones_idx = None
        for i, block in enumerate(all_blocks):
            if block.get("type") in ["heading2", "heading_2"]:
                content = str(block.get("content", "") or block.get("text", ""))
                if "Onboarding Milestones" in content and "🏆" in content:
                    milestones_idx = i
                    break
    
        if milestones_idx is None:
            errors.append("[X] '🏆 Onboarding Milestones' heading not found")
        else:
            checks_passed.append("[C] '🏆 Onboarding Milestones' heading found")
    
        # Check for divider before milestones
        divider_before = False
        if milestones_idx > 0:
            for i in range(max(0, milestones_idx - 3), milestones_idx):
                if all_blocks[i].get("type") == "divider":
                    divider_before = True
                    break
    
        if not divider_before:
            errors.append("[X] Divider not found before Onboarding Milestones")
        else:
            checks_passed.append("[C] Divider found before Onboarding Milestones")
    
        # Check for yellow callout
        callout_found = False
        for i in range(milestones_idx + 1, min(milestones_idx + 5, len(all_blocks))):
            block = all_blocks[i]
            if block.get("type") == "callout":
                bg = block.get("properties", {}).get("backgroundColor", "")
                icon = block.get("properties", {}).get("icon", "")
                if "yellow" in bg and "⭐" in icon:
                    callout_found = True
                    break
    
        if not callout_found:
            errors.append("[X] Yellow callout with star icon not found")
        else:
            checks_passed.append("[C] Yellow callout with star icon found")
    
        # Find Week 1 and Month 1 headings
        week1_idx = None
        month1_idx = None
    
        for i in range(milestones_idx + 1, len(all_blocks)):
            block = all_blocks[i]
            if block.get("type") in ["heading2", "heading_2"]:
                break
            if block.get("type") in ["heading3", "heading_3"]:
                content = str(block.get("content", "") or block.get("text", ""))
                if "Week 1 Achievements" in content:
                    week1_idx = i
                elif "Month 1 Goals" in content:
                    month1_idx = i
    
        if week1_idx is None:
            errors.append("[X] 'Week 1 Achievements' heading_3 not found")
        else:
            checks_passed.append("[C] 'Week 1 Achievements' heading_3 found")
    
        if month1_idx is None:
            errors.append("[X] 'Month 1 Goals' heading_3 not found")
        else:
            checks_passed.append("[C] 'Month 1 Goals' heading_3 found")
    
        # Count unchecked todos under each section
        week1_todos = 0
        for i in range(week1_idx + 1, month1_idx):
            if all_blocks[i].get("type") == "todo" and not all_blocks[i].get("properties", {}).get("checked"):
                week1_todos += 1
    
        month1_todos = 0
        for i in range(month1_idx + 1, len(all_blocks)):
            block = all_blocks[i]
            if block.get("type") in ["heading2", "heading_2", "heading3", "heading_3"]:
                break
            if block.get("type") == "todo" and not block.get("properties", {}).get("checked"):
                month1_todos += 1
    
        if week1_todos < 3:
            errors.append(f"[X] Week 1 has {week1_todos} todos, expected 3")
        else:
            checks_passed.append(f"[C] Week 1 has {week1_todos} todos, expected 3")
    
        if month1_todos < 3:
            errors.append(f"[X] Month 1 has {month1_todos} todos, expected 3")
        else:
            checks_passed.append(f"[C] Month 1 has {month1_todos} todos, expected 3")
    
        # Check for quote block
        quote_found = False
        for i in range(milestones_idx, len(all_blocks)):
            if all_blocks[i].get("type") == "quote":
                content = str(all_blocks[i].get("content", "") or all_blocks[i].get("text", ""))
                if "journey" in content.lower():
                    quote_found = True
                    break
    
        if not quote_found:
            errors.append("[X] Quote block not found")
        else:
            checks_passed.append("[C] Quote block found")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

    # -----------------------------------------------------------------------------
    # reorganize-handbook-swap-work-benefits-v2
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_reorganize_handbook_swap_work_benefits(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Task: Swap Work Policies and Benefits sections, add new benefits subsection.
    
    Validates:
    1. Benefits section appears where Work Policies was
    2. Work Policies appears at end
    3. New Benefits for 2024 heading_3 with bulleted items
    4. Divider and quote before Work Policies in new location
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    # Find Company Handbook page
    try:
        page_results = final_state_backend.query({
            "collection": "pages",
            "filter": {"title": "Company Handbook"}
        })
    
        if not page_results:
            errors.append("[X] Company Handbook page not found")
        else:
            checks_passed.append("[C] Company Handbook page found")
    
        page = page_results[0]
        # Query blocks collection for this page
        all_blocks = final_state_backend.query({
            "collection": "blocks",
            "filter": {"pageId": page.get("_id")}
        })
    
        # Find section headings and their indices
        benefits_idx = None
        work_policies_idx = None
        our_values_idx = None
    
        for i, block in enumerate(all_blocks):
            if block.get("type") in ["heading2", "heading_2"]:
                content = str(block.get("content", "") or block.get("text", ""))
                if "Benefits" in content:
                    benefits_idx = i
                elif "Work Policies" in content:
                    work_policies_idx = i
                elif "Our Values" in content:
                    our_values_idx = i
    
        if benefits_idx is None:
            errors.append("[X] Benefits heading not found")
        else:
            checks_passed.append("[C] Benefits heading found")
    
        if work_policies_idx is None:
            errors.append("[X] Work Policies heading not found")
        else:
            checks_passed.append("[C] Work Policies heading found")
    
        if our_values_idx is None:
            errors.append("[X] Our Values heading not found")
        else:
            checks_passed.append("[C] Our Values heading found")
    
        # Benefits should come after Our Values (swapped position)
        if benefits_idx <= our_values_idx:
            errors.append("[X] Benefits should appear after Our Values")
        else:
            checks_passed.append("[C] Benefits should appear after Our Values")
    
        # Work Policies should come after Benefits (swapped position)
        if work_policies_idx <= benefits_idx:
            errors.append("[X] Work Policies should appear after Benefits")
        else:
            checks_passed.append("[C] Work Policies should appear after Benefits")
    
        # Look for New Benefits for 2024 heading_3
        new_benefits_found = False
        for i in range(benefits_idx + 1, work_policies_idx):
            block = all_blocks[i]
            if block.get("type") in ["heading3", "heading_3"]:
                content = str(block.get("content", "") or block.get("text", ""))
                if "New Benefits for 2024" in content and "🌟" in content:
                    new_benefits_found = True
                    break
    
        if not new_benefits_found:
            errors.append("[X] '🌟 New Benefits for 2024' heading_3 not found")
        else:
            checks_passed.append("[C] '🌟 New Benefits for 2024' heading_3 found")
    
        # Check for bulleted items mentioning the new benefits
        required_benefits = ["Mental health", "wellness stipend", "team retreats"]
        found_benefits = 0
    
        for i in range(benefits_idx, work_policies_idx):
            block = all_blocks[i]
            if block.get("type") == "bulletedList":
                content = str(block.get("content", "") or block.get("text", "")).lower()
                for req in required_benefits:
                    if req.lower() in content:
                        found_benefits += 1
                        break
    
        if found_benefits < 3:
            errors.append(f"[X] Found {found_benefits} of 3 required new benefits")
        else:
            checks_passed.append(f"[C] Found {found_benefits} of 3 required new benefits")
    
        # Check for divider before Work Policies
        divider_found = False
        for i in range(max(0, work_policies_idx - 3), work_policies_idx):
            if all_blocks[i].get("type") == "divider":
                divider_found = True
                break
    
        if not divider_found:
            errors.append("[X] Divider not found before Work Policies")
        else:
            checks_passed.append("[C] Divider found before Work Policies")
    
        # Check for quote after divider
        quote_found = False
        for i in range(max(0, work_policies_idx - 3), work_policies_idx):
            if all_blocks[i].get("type") == "quote":
                content = str(all_blocks[i].get("content", "") or all_blocks[i].get("text", ""))
                if "work-life balance" in content.lower():
                    quote_found = True
                    break
    
        if not quote_found:
            errors.append("[X] Quote block not found before Work Policies")
        else:
            checks_passed.append("[C] Quote block found before Work Policies")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

    # -----------------------------------------------------------------------------
    # reorganize-handbook-swap-values-benefits-add-remote-v2
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_reorganize_handbook_swap_values_benefits_add_remote(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Task: Swap Our Values and Benefits, add Remote Work Resources section.
    
    Validates:
    1. Benefits appears where Our Values was
    2. Our Values appears after Work Policies
    3. Remote Work Resources section between Benefits and Work Policies
    4. Divider before Remote Work Resources
    5. Blue callout with laptop icon
    6. Three bookmarks with URLs and captions
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    # Find Company Handbook page
    try:
        page_results = final_state_backend.query({
            "collection": "pages",
            "filter": {"title": "Company Handbook"}
        })
    
        if not page_results:
            errors.append("[X] Company Handbook page not found")
        else:
            checks_passed.append("[C] Company Handbook page found")
    
        page = page_results[0]
        # Query blocks collection for this page
        all_blocks = final_state_backend.query({
            "collection": "blocks",
            "filter": {"pageId": page.get("_id")}
        })
    
        # Find section headings
        benefits_idx = None
        our_values_idx = None
        work_policies_idx = None
        remote_work_idx = None
    
        for i, block in enumerate(all_blocks):
            if block.get("type") in ["heading2", "heading_2"]:
                content = str(block.get("content", "") or block.get("text", ""))
                if "Benefits" in content:
                    benefits_idx = i
                elif "Our Values" in content:
                    our_values_idx = i
                elif "Work Policies" in content:
                    work_policies_idx = i
                elif "Remote Work Resources" in content and "🌍" in content:
                    remote_work_idx = i
    
        if benefits_idx is None:
            errors.append("[X] Benefits heading not found")
        else:
            checks_passed.append("[C] Benefits heading found")
    
        if our_values_idx is None:
            errors.append("[X] Our Values heading not found")
        else:
            checks_passed.append("[C] Our Values heading found")
    
        if work_policies_idx is None:
            errors.append("[X] Work Policies heading not found")
        else:
            checks_passed.append("[C] Work Policies heading found")
    
        if remote_work_idx is None:
            errors.append("[X] '🌍 Remote Work Resources' heading not found")
        else:
            checks_passed.append("[C] '🌍 Remote Work Resources' heading found")
    
        # Verify ordering: Benefits should be early, Remote Work in middle, Work Policies, then Our Values at end
        if benefits_idx > our_values_idx:
            errors.append("[X] Benefits should appear before Our Values")
        else:
            checks_passed.append("[C] Benefits should appear before Our Values")
    
        if remote_work_idx <= benefits_idx:
            errors.append("[X] Remote Work Resources should appear after Benefits")
        else:
            checks_passed.append("[C] Remote Work Resources should appear after Benefits")
    
        if remote_work_idx >= work_policies_idx:
            errors.append("[X] Remote Work Resources should appear before Work Policies")
        else:
            checks_passed.append("[C] Remote Work Resources should appear before Work Policies")
    
        if our_values_idx <= work_policies_idx:
            errors.append("[X] Our Values should appear after Work Policies")
        else:
            checks_passed.append("[C] Our Values should appear after Work Policies")
    
        # Check for blue callout under Remote Work Resources
        callout_found = False
        for i in range(remote_work_idx + 1, min(remote_work_idx + 5, len(all_blocks))):
            block = all_blocks[i]
            if block.get("type") == "callout":
                bg = block.get("properties", {}).get("backgroundColor", "")
                icon = block.get("properties", {}).get("icon", "")
                if "blue" in bg and "💻" in icon:
                    callout_found = True
                    break
    
        if not callout_found:
            errors.append("[X] Blue callout with laptop icon not found")
        else:
            checks_passed.append("[C] Blue callout with laptop icon found")
    
        # Check for divider before Remote Work Resources
        divider_found = False
        for i in range(max(0, remote_work_idx - 3), remote_work_idx):
            if all_blocks[i].get("type") == "divider":
                divider_found = True
                break
    
        if not divider_found:
            errors.append("[X] Divider not found before Remote Work Resources section")
        else:
            checks_passed.append("[C] Divider found before Remote Work Resources section")
    
        # Check for three bookmarks with specific URLs and captions
        required_bookmarks = [
            ("company.slack.com", "communication"),
            ("vpn.company.com", "vpn"),
            ("tools.company.com", "toolkit")
        ]
        found_bookmarks = 0
    
        for i in range(remote_work_idx, work_policies_idx):
            block = all_blocks[i]
            if block.get("type") == "bookmark":
                url = str(block.get("properties", {}).get("url", "") or block.get("url", ""))
                caption = str(block.get("properties", {}).get("caption", "")).lower()
            
                for req_url, caption_keyword in required_bookmarks:
                    if req_url in url and caption_keyword in caption:
                        found_bookmarks += 1
                        break
    
        if found_bookmarks < 3:
            errors.append(f"[X] Found {found_bookmarks} of 3 required bookmarks with URLs and captions")
        else:
            checks_passed.append(f"[C] Found {found_bookmarks} of 3 required bookmarks with URLs and captions")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

    # -----------------------------------------------------------------------------
    # add-getting-started-troubleshooting-v2
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_add_getting_started_troubleshooting(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Task: Add progress callout and troubleshooting section to Getting Started.
    
    Validates:
    1. Green progress callout with ✅ icon and calculated percentage
    2. Callout between checklist heading and first todo
    3. Divider before Troubleshooting Guide
    4. Troubleshooting Guide heading_2 at end
    5. Common Issues heading_3 with numbered items
    6. Bookmark to help.notion.com with caption
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    # Find Getting Started page
    try:
        page_results = final_state_backend.query({
            "collection": "pages",
            "filter": {"title": "Getting Started"}
        })
    
        if not page_results:
            errors.append("[X] Getting Started page not found")
        else:
            checks_passed.append("[C] Getting Started page found")
    
        page = page_results[0]
        # Query blocks collection for this page
        all_blocks = final_state_backend.query({
            "collection": "blocks",
            "filter": {"pageId": page.get("_id")}
        })
    
        # Find Quick Start Checklist heading
        checklist_idx = None
        for i, block in enumerate(all_blocks):
            if block.get("type") in ["heading2", "heading_2"]:
                content = str(block.get("content", "") or block.get("text", ""))
                if "Quick Start Checklist" in content:
                    checklist_idx = i
                    break
    
        if checklist_idx is None:
            errors.append("[X] Quick Start Checklist heading not found")
        else:
            checks_passed.append("[C] Quick Start Checklist heading found")
    
        # Check for green progress callout after checklist heading
        progress_callout_found = False
        for i in range(checklist_idx + 1, min(checklist_idx + 5, len(all_blocks))):
            block = all_blocks[i]
            if block.get("type") == "callout":
                bg = block.get("properties", {}).get("backgroundColor", "")
                icon = block.get("properties", {}).get("icon", "")
                content = str(block.get("content", "") or block.get("text", ""))
                if "green" in bg and "✅" in icon and "Progress:" in content and "%" in content:
                    progress_callout_found = True
                    break
    
        if not progress_callout_found:
            errors.append("[X] Green progress callout with ✅ icon not found")
        else:
            checks_passed.append("[C] Green progress callout with ✅ icon found")
    
        # Find Troubleshooting Guide heading
        troubleshooting_idx = None
        for i, block in enumerate(all_blocks):
            if block.get("type") in ["heading2", "heading_2"]:
                content = str(block.get("content", "") or block.get("text", ""))
                if "Troubleshooting Guide" in content and "🔧" in content:
                    troubleshooting_idx = i
                    break
    
        if troubleshooting_idx is None:
            errors.append("[X] '🔧 Troubleshooting Guide' heading not found")
        else:
            checks_passed.append("[C] '🔧 Troubleshooting Guide' heading found")
    
        # Check for divider before Troubleshooting Guide
        divider_found = False
        for i in range(max(0, troubleshooting_idx - 3), troubleshooting_idx):
            if all_blocks[i].get("type") == "divider":
                divider_found = True
                break
    
        if not divider_found:
            errors.append("[X] Divider not found before Troubleshooting Guide")
        else:
            checks_passed.append("[C] Divider found before Troubleshooting Guide")
    
        # Check for Common Issues heading_3
        common_issues_found = False
        for i in range(troubleshooting_idx + 1, len(all_blocks)):
            block = all_blocks[i]
            if block.get("type") in ["heading2", "heading_2"]:
                break
            if block.get("type") in ["heading3", "heading_3"]:
                content = str(block.get("content", "") or block.get("text", ""))
                if "Common Issues" in content and "❓" in content:
                    common_issues_found = True
                    break
    
        if not common_issues_found:
            errors.append("[X] '❓ Common Issues' heading_3 not found")
        else:
            checks_passed.append("[C] '❓ Common Issues' heading_3 found")
    
        # Check for numbered list items
        numbered_count = 0
        for i in range(troubleshooting_idx, len(all_blocks)):
            block = all_blocks[i]
            if block.get("type") in ["heading2", "heading_2"]:
                if i > troubleshooting_idx:
                    break
            if block.get("type") == "numberedList":
                numbered_count += 1
    
        if numbered_count < 3:
            errors.append(f"[X] Found {numbered_count} numbered troubleshooting items, expected 3")
        else:
            checks_passed.append(f"[C] Found {numbered_count} numbered troubleshooting items, expected 3")
    
        # Check for bookmark to help.notion.com with caption
        bookmark_found = False
        for i in range(troubleshooting_idx, len(all_blocks)):
            block = all_blocks[i]
            if block.get("type") == "bookmark":
                url = str(block.get("properties", {}).get("url", "") or block.get("url", ""))
                caption = str(block.get("properties", {}).get("caption", "")).lower()
                if "help.notion.com" in url and "troubleshooting" in caption:
                    bookmark_found = True
                    break
    
        if not bookmark_found:
            errors.append("[X] Bookmark to help.notion.com with caption not found")
        else:
            checks_passed.append("[C] Bookmark to help.notion.com with caption found")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

    # -----------------------------------------------------------------------------
    # create-onboarding-checklist-sibling-v2
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_create_onboarding_checklist_sibling(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Task: Create Onboarding Checklist page as sibling to Onboarding Guide.
    
    Validates:
    1. Page created at same level as Onboarding Guide
    2. Week 1 and Week 2 task sections with todos
    3. Green welcome callout
    4. Progress Tracking section with dates
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    # Find Onboarding Guide page
    try:
        guide_results = final_state_backend.query({
            "collection": "pages",
            "filter": {"title": "Onboarding Guide"}
        })
    
        if not guide_results:
            errors.append("[X] Onboarding Guide page not found")
        else:
            checks_passed.append("[C] Onboarding Guide page found")
    
        guide = guide_results[0]
        parent_id = guide.get("parentId")
    
        # Find Onboarding Checklist page with same parent
        checklist_results = final_state_backend.query({
            "collection": "pages",
            "filter": {"title": "Onboarding Checklist", "parentId": parent_id}
        })
    
        if not checklist_results:
            errors.append("[X] Onboarding Checklist page not found as sibling")
        else:
            checks_passed.append("[C] Onboarding Checklist page found as sibling")
    
        checklist = checklist_results[0]
        # Query blocks collection for this page
        all_blocks = final_state_backend.query({
            "collection": "blocks",
            "filter": {"pageId": checklist.get("_id")}
        })
    
        # Check for heading_1
        if not all_blocks or all_blocks[0].get("type") not in ["heading1", "heading_1"]:
            errors.append("[X] Page should start with heading_1")
        else:
            checks_passed.append("[C] Page should start with heading_1")
    
        # Find Week 1 and Week 2 headings
        week1_idx = None
        week2_idx = None
    
        for i, block in enumerate(all_blocks):
            if block.get("type") in ["heading3", "heading_3"]:
                content = str(block.get("content", "") or block.get("text", ""))
                if "Week 1 Tasks" in content:
                    week1_idx = i
                elif "Week 2 Tasks" in content:
                    week2_idx = i
    
        if week1_idx is None:
            errors.append("[X] 'Week 1 Tasks' heading_3 not found")
        else:
            checks_passed.append("[C] 'Week 1 Tasks' heading_3 found")
    
        if week2_idx is None:
            errors.append("[X] 'Week 2 Tasks' heading_3 not found")
        else:
            checks_passed.append("[C] 'Week 2 Tasks' heading_3 found")
    
        # Count todos under each week
        week1_todos = 0
        for i in range(week1_idx + 1, week2_idx):
            if all_blocks[i].get("type") == "todo":
                week1_todos += 1
    
        week2_todos = 0
        for i in range(week2_idx + 1, len(all_blocks)):
            block = all_blocks[i]
            if block.get("type") in ["heading2", "heading_2", "heading3", "heading_3"]:
                break
            if block.get("type") == "todo":
                week2_todos += 1
    
        if week1_todos < 4:
            errors.append(f"[X] Week 1 has {week1_todos} todos, expected at least 4")
        else:
            checks_passed.append(f"[C] Week 1 has {week1_todos} todos, expected at least 4")
    
        if week2_todos < 3:
            errors.append(f"[X] Week 2 has {week2_todos} todos, expected at least 3")
        else:
            checks_passed.append(f"[C] Week 2 has {week2_todos} todos, expected at least 3")
    
        # Check for green callout
        callout_found = False
        for block in all_blocks:
            if block.get("type") == "callout":
                bg = block.get("properties", {}).get("backgroundColor", "")
                icon = block.get("properties", {}).get("icon", "")
                content = str(block.get("content", "") or block.get("text", ""))
                if "green" in bg and "🎉" in icon and "Welcome" in content:
                    callout_found = True
                    break
    
        if not callout_found:
            errors.append("[X] Green welcome callout not found")
        else:
            checks_passed.append("[C] Green welcome callout found")
    
        # Check for Progress Tracking section
        progress_tracking_found = False
        for block in all_blocks:
            if block.get("type") in ["heading2", "heading_2"]:
                content = str(block.get("content", "") or block.get("text", ""))
                if "Progress Tracking" in content and "📊" in content:
                    progress_tracking_found = True
                    break
    
        if not progress_tracking_found:
            errors.append("[X] '📊 Progress Tracking' heading not found")
        else:
            checks_passed.append("[C] '📊 Progress Tracking' heading found")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

    # -----------------------------------------------------------------------------
    # add-getting-started-advanced-features-v2
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_add_getting_started_advanced_features(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Task: Add Advanced Features subsection after Quick Start Checklist todos.
    
    Validates:
    1. Advanced Features heading_3 in correct position
    2. Blue callout with 💡 icon and power features text
    3. Three unchecked todos
    4. Bold progress update paragraph with count
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    # Find Getting Started page
    try:
        page_results = final_state_backend.query({
            "collection": "pages",
            "filter": {"title": "Getting Started"}
        })
    
        if not page_results:
            errors.append("[X] Getting Started page not found")
        else:
            checks_passed.append("[C] Getting Started page found")
    
        page = page_results[0]
        # Query blocks collection for this page
        all_blocks = final_state_backend.query({
            "collection": "blocks",
            "filter": {"pageId": page.get("_id")}
        })
    
        # Find Advanced Features heading
        advanced_idx = None
        for i, block in enumerate(all_blocks):
            if block.get("type") in ["heading3", "heading_3"]:
                content = str(block.get("content", "") or block.get("text", ""))
                if "Advanced Features" in content and "🚀" in content:
                    advanced_idx = i
                    break
    
        if advanced_idx is None:
            errors.append("[X] '🚀 Advanced Features' heading_3 not found")
        else:
            checks_passed.append("[C] '🚀 Advanced Features' heading_3 found")
    
        # Check for blue callout after Advanced Features
        callout_found = False
        for i in range(advanced_idx + 1, min(advanced_idx + 3, len(all_blocks))):
            block = all_blocks[i]
            if block.get("type") == "callout":
                bg = block.get("properties", {}).get("backgroundColor", "")
                icon = block.get("properties", {}).get("icon", "")
                content = str(block.get("content", "") or block.get("text", ""))
                if "blue" in bg and "💡" in icon and "power features" in content.lower():
                    callout_found = True
                    break
    
        if not callout_found:
            errors.append("[X] Blue callout with 💡 icon and power features text not found")
        else:
            checks_passed.append("[C] Blue callout with 💡 icon and power features text found")
    
        # Check for three unchecked todos
        required_todos = ["database views", "keyboard shortcuts", "automation"]
        found_todos = 0
    
        for i in range(advanced_idx + 1, len(all_blocks)):
            block = all_blocks[i]
            if block.get("type") in ["heading2", "heading_2", "heading3", "heading_3"]:
                if i > advanced_idx + 1:
                    break
            if block.get("type") == "todo" and not block.get("properties", {}).get("checked"):
                content = str(block.get("content", "") or block.get("text", "")).lower()
                for req in required_todos:
                    if req in content:
                        found_todos += 1
                        break
    
        if found_todos < 3:
            errors.append(f"[X] Found {found_todos} of 3 required advanced feature todos")
        else:
            checks_passed.append(f"[C] Found {found_todos} of 3 required advanced feature todos")
    
        # Check for progress update paragraph
        progress_found = False
        for block in all_blocks:
            if block.get("type") == "paragraph":
                content = str(block.get("content", "") or block.get("text", ""))
                if "Progress Update" in content and "features left" in content:
                    progress_found = True
                    break
    
        if not progress_found:
            errors.append("[X] Progress update paragraph not found")
        else:
            checks_passed.append("[C] Progress update paragraph found")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

    # -----------------------------------------------------------------------------
    # add-bug-tracker-urgent-section-v2
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_add_bug_tracker_urgent_section(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Task: Add Urgent priority section and statistics callout to Bug Tracker.
    
    Validates:
    1. Urgent heading_2 positioned between Critical and Medium
    2. Four unchecked urgent todos
    3. New todo added to Low Priority section
    4. Red statistics callout with 📊 icon at top with accurate counts
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    # Find Bug Tracker page
    try:
        page_results = final_state_backend.query({
            "collection": "pages",
            "filter": {"title": "Bug Tracker"}
        })
    
        if not page_results:
            errors.append("[X] Bug Tracker page not found")
        else:
            checks_passed.append("[C] Bug Tracker page found")
    
        page = page_results[0]
        # Query blocks collection for this page
        all_blocks = final_state_backend.query({
            "collection": "blocks",
            "filter": {"pageId": page.get("_id")}
        })
    
        # Find section headings
        critical_idx = None
        urgent_idx = None
        medium_idx = None
        low_idx = None
    
        for i, block in enumerate(all_blocks):
            if block.get("type") in ["heading2", "heading_2"]:
                content = str(block.get("content", "") or block.get("text", ""))
                if "Critical" in content:
                    critical_idx = i
                elif "Urgent - Customer Impacting" in content and "🔥" in content:
                    urgent_idx = i
                elif "Medium Priority" in content:
                    medium_idx = i
                elif "Low Priority" in content:
                    low_idx = i
    
        if critical_idx is None:
            errors.append("[X] Critical Bugs heading not found")
        else:
            checks_passed.append("[C] Critical Bugs heading found")
    
        if urgent_idx is None:
            errors.append("[X] '🔥 Urgent - Customer Impacting' heading not found")
        else:
            checks_passed.append("[C] '🔥 Urgent - Customer Impacting' heading found")
    
        if medium_idx is None:
            errors.append("[X] Medium Priority heading not found")
        else:
            checks_passed.append("[C] Medium Priority heading found")
    
        # Verify Urgent is between Critical and Medium
        if not (critical_idx < urgent_idx < medium_idx):
            errors.append("[X] Urgent section must be positioned between Critical and Medium")
        else:
            checks_passed.append("[C] Urgent section must be positioned between Critical and Medium")
    
        # Count urgent todos
        urgent_todos = 0
        for i in range(urgent_idx + 1, medium_idx):
            if all_blocks[i].get("type") == "todo" and not all_blocks[i].get("checked"):
                urgent_todos += 1
    
        if urgent_todos < 4:
            errors.append(f"[X] Found {urgent_todos} urgent todos, expected 4")
        else:
            checks_passed.append(f"[C] Found {urgent_todos} urgent todos, expected 4")
    
        # Check for new todo in Low Priority about dark mode
        if low_idx is not None:
            dark_mode_found = False
            for i in range(low_idx + 1, len(all_blocks)):
                block = all_blocks[i]
                if block.get("type") in ["heading2", "heading_2"]:
                    break
                if block.get("type") == "todo":
                    content = str(block.get("content", "") or block.get("text", ""))
                    if "dark mode" in content.lower():
                        dark_mode_found = True
                        break
        
            if not dark_mode_found:
                errors.append("[X] Dark mode contrast todo not found in Low Priority")
            else:
                checks_passed.append("[C] Dark mode contrast todo found in Low Priority")
    
        # Check for red statistics callout near top
        stats_callout_found = False
        for i in range(0, min(10, len(all_blocks))):
            block = all_blocks[i]
            if block.get("type") == "callout":
                bg = block.get("properties", {}).get("backgroundColor", "")
                icon = block.get("properties", {}).get("icon", "")
                content = str(block.get("content", "") or block.get("text", ""))
                if "red" in bg and "📊" in icon and "Total bugs tracked" in content and "%" in content:
                    stats_callout_found = True
                    break
    
        if not stats_callout_found:
            errors.append("[X] Red statistics callout with 📊 icon not found near top of page")
        else:
            checks_passed.append("[C] Red statistics callout with 📊 icon found near top of page")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

    # -----------------------------------------------------------------------------
    # create-cross-project-task-tracker-v2
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_create_cross_project_task_tracker(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Task: Create aggregated task tracker analyzing todos from multiple pages.
    
    Validates:
    1. Page created as sibling to Project Roadmap
    2. Summary callout at top with statistics
    3. Multiple page sections with heading_2
    4. Progress callouts with correct colors based on completion
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    # Find Project Roadmap page
    try:
        roadmap_results = final_state_backend.query({
            "collection": "pages",
            "filter": {"title": "Project Roadmap"}
        })
    
        if not roadmap_results:
            errors.append("[X] Project Roadmap page not found")
        else:
            checks_passed.append("[C] Project Roadmap page found")
    
        roadmap = roadmap_results[0]
        parent_id = roadmap.get("parentId")
    
        # Find Cross-Project Task Tracker page
        tracker_results = final_state_backend.query({
            "collection": "pages",
            "filter": {"title": "Cross-Project Task Tracker", "parentId": parent_id}
        })
    
        if not tracker_results:
            # Try without emoji
            tracker_results = final_state_backend.query({
                "collection": "pages",
                "filter": {"parentId": parent_id}
            })
            tracker_results = [p for p in tracker_results if "Cross-Project Task Tracker" in p.get("title", "")]
    
        if not tracker_results:
            errors.append("[X] Cross-Project Task Tracker page not found as sibling")
        else:
            checks_passed.append("[C] Cross-Project Task Tracker page found as sibling")
    
        tracker = tracker_results[0]
        # Query blocks collection for this page
        all_blocks = final_state_backend.query({
            "collection": "blocks",
            "filter": {"pageId": tracker.get("_id")}
        })
    
        # Check for heading_1
        if not all_blocks or all_blocks[0].get("type") not in ["heading1", "heading_1"]:
            errors.append("[X] Page should start with heading_1")
        else:
            checks_passed.append("[C] Page should start with heading_1")
    
        # Check for summary callout near top
        summary_callout_found = False
        for i in range(0, min(5, len(all_blocks))):
            block = all_blocks[i]
            if block.get("type") == "callout":
                bg = block.get("properties", {}).get("backgroundColor", "")
                icon = block.get("properties", {}).get("icon", "")
                content = str(block.get("content", "") or block.get("text", ""))
                if "blue" in bg and "📊" in icon and "Tracking" in content and "projects" in content.lower():
                    summary_callout_found = True
                    break
    
        if not summary_callout_found:
            errors.append("[X] Summary callout with project statistics not found")
        else:
            checks_passed.append("[C] Summary callout with project statistics found")
    
        # Count project sections (heading_2 blocks with folder emoji)
        project_sections = 0
        for block in all_blocks:
            if block.get("type") in ["heading2", "heading_2"]:
                content = str(block.get("content", "") or block.get("text", ""))
                if "📁" in content:
                    project_sections += 1
    
        if project_sections < 2:
            errors.append(f"[X] Found {project_sections} project sections, expected at least 2")
        else:
            checks_passed.append(f"[C] Found {project_sections} project sections, expected at least 2")
    
        # Check for progress callouts (should have different colors)
        callout_colors = set()
        for block in all_blocks:
            if block.get("type") == "callout":
                content = str(block.get("content", "") or block.get("text", ""))
                if "Progress:" in content:
                    bg = block.get("properties", {}).get("backgroundColor", "")
                    callout_colors.add(bg)
    
        if len(callout_colors) < 1:
            errors.append("[X] Progress callouts not found")
        else:
            checks_passed.append("[C] Progress callouts found")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

    # -----------------------------------------------------------------------------
    # enhance-onboarding-guide-comprehensive-v2
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_enhance_onboarding_guide_comprehensive(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Task: Comprehensive enhancement of Onboarding Guide with multiple sections.
    
    Validates:
    1. Green callout at top with time estimate
    2. Progress Tracking section with numbered items and todos
    3. Multiple bookmarks added after numbered lists
    4. Welcome image at end
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    # Find Onboarding Guide page
    try:
        page_results = final_state_backend.query({
            "collection": "pages",
            "filter": {"title": "Onboarding Guide"}
        })
    
        if not page_results:
            errors.append("[X] Onboarding Guide page not found")
        else:
            checks_passed.append("[C] Onboarding Guide page found")
    
        page = page_results[0]
        # Query blocks collection for this page
        all_blocks = final_state_backend.query({
            "collection": "blocks",
            "filter": {"pageId": page.get("_id")}
        })
    
        # Check for green callout near top
        green_callout_found = False
        for i in range(0, min(10, len(all_blocks))):
            block = all_blocks[i]
            if block.get("type") == "callout":
                bg = block.get("properties", {}).get("backgroundColor", "")
                icon = block.get("properties", {}).get("icon", "")
                content = str(block.get("content", "") or block.get("text", ""))
                if "green" in bg and "🚀" in icon and "2 hours" in content:
                    green_callout_found = True
                    break
    
        if not green_callout_found:
            errors.append("[X] Green callout with time estimate not found at top")
        else:
            checks_passed.append("[C] Green callout with time estimate found at top")
    
        # Find Progress Tracking section and check for todos
        progress_tracking_found = False
        progress_tracking_idx = -1
        for idx, block in enumerate(all_blocks):
            if block.get("type") in ["heading2", "heading_2"]:
                content = str(block.get("content", "") or block.get("text", ""))
                if "Progress Tracking" in content and "📊" in content:
                    progress_tracking_found = True
                    progress_tracking_idx = idx
                    break
    
        if not progress_tracking_found:
            errors.append("[X] '📊 Progress Tracking' section not found")
        else:
            checks_passed.append("[C] '📊 Progress Tracking' section found")
    
        # Check for todos in Progress Tracking section (should have at least 4 unchecked todos)
        todo_count = 0
        for i in range(progress_tracking_idx + 1, min(progress_tracking_idx + 20, len(all_blocks))):
            if all_blocks[i].get("type") == "todo":
                checked = all_blocks[i].get("properties", {}).get("checked", True)
                if not checked:
                    todo_count += 1
            elif all_blocks[i].get("type") in ["heading2", "heading_2"]:
                break  # Stop at next heading
    
        if todo_count < 4:
            errors.append(f"[X] Found {todo_count} unchecked todos in Progress Tracking, expected at least 4")
        else:
            checks_passed.append(f"[C] Found {todo_count} unchecked todos in Progress Tracking, expected at least 4")
    
        # Count bookmarks (should have multiple)
        bookmark_count = sum(1 for b in all_blocks if b.get("type") == "bookmark")
        if bookmark_count < 5:
            errors.append(f"[X] Found {bookmark_count} bookmarks, expected at least 5")
        else:
            checks_passed.append(f"[C] Found {bookmark_count} bookmarks, expected at least 5")
    
        # Check for image at end
        image_found = False
        for i in range(len(all_blocks) - 5, len(all_blocks)):
            if i >= 0 and all_blocks[i].get("type") == "image":
                url = str(all_blocks[i].get("content", "") or all_blocks[i].get("url", ""))
                caption = str(all_blocks[i].get("properties", {}).get("caption", "") or all_blocks[i].get("caption", ""))
                if "welcome" in caption.lower():
                    image_found = True
                    break
    
        if not image_found:
            errors.append("[X] Welcome image not found at end of page")
        else:
            checks_passed.append("[C] Welcome image found at end of page")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

    # -----------------------------------------------------------------------------
    # add-sprint-planning-commitment-summary-v2
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_add_sprint_planning_commitment_summary(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Task: Add Sprint Commitment Summary with team capacity and goals.
    
    Validates:
    1. Sprint Commitment Summary heading_2 between Next Steps and Action Items
    2. Bold paragraph with sprint duration
    3. Team capacity bulleted list with three members
    4. Yellow velocity callout
    5. Sprint Goals heading_3 with three numbered items
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    # Find Sprint Planning page
    # Use text search to find pages with "Sprint Planning" instead of fetching all pages
    try:
        page_results = final_state_backend.query({
            "collection": "pages",
            "filter": {"$text": {"$search": "Sprint Planning"}}
        })
    
        sprint_page = None
        for page in page_results:
            if "Sprint Planning" in page.get("title", ""):
                sprint_page = page
                break
    
        if not sprint_page:
            errors.append("[X] Sprint Planning page not found")
        else:
            checks_passed.append("[C] Sprint Planning page found")
    
        # Query blocks collection for this page
        all_blocks = final_state_backend.query({
            "collection": "blocks",
            "filter": {"pageId": sprint_page.get("_id")}
        })
    
        # Find Sprint Commitment Summary heading
        commitment_idx = None
        for i, block in enumerate(all_blocks):
            if block.get("type") in ["heading2", "heading_2"]:
                content = str(block.get("content", "") or block.get("text", ""))
                if "Sprint Commitment Summary" in content and "📋" in content:
                    commitment_idx = i
                    break
    
        if commitment_idx is None:
            errors.append("[X] '📋 Sprint Commitment Summary' heading not found")
        else:
            checks_passed.append("[C] '📋 Sprint Commitment Summary' heading found")
    
        # Check for paragraph with sprint duration
        duration_found = False
        for i in range(commitment_idx + 1, min(commitment_idx + 10, len(all_blocks))):
            block = all_blocks[i]
            if block.get("type") == "paragraph":
                content = str(block.get("content", "") or block.get("text", ""))
                if "Sprint Duration" in content and ("January" in content or "2025" in content):
                    duration_found = True
                    break
    
        if not duration_found:
            errors.append("[X] Paragraph with sprint duration not found")
        else:
            checks_passed.append("[C] Paragraph with sprint duration found")
    
        # Check for team capacity bullets
        team_members = ["Alice", "Bob", "Carol"]
        found_members = 0
    
        for i in range(commitment_idx, len(all_blocks)):
            block = all_blocks[i]
            if block.get("type") in ["heading2", "heading_2"]:
                if i > commitment_idx:
                    break
            if block.get("type") == "bulletedList":
                content = str(block.get("content", "") or block.get("text", ""))
                for member in team_members:
                    if member in content and "story points" in content.lower():
                        found_members += 1
                        break
    
        if found_members < 3:
            errors.append(f"[X] Found {found_members} team capacity bullets, expected 3")
        else:
            checks_passed.append(f"[C] Found {found_members} team capacity bullets, expected 3")
    
        # Check for yellow velocity callout with ⚡ icon
        velocity_callout_found = False
        for i in range(commitment_idx, len(all_blocks)):
            block = all_blocks[i]
            if block.get("type") in ["heading2", "heading_2"]:
                if i > commitment_idx:
                    break
            if block.get("type") == "callout":
                bg = block.get("properties", {}).get("backgroundColor", "")
                icon = block.get("properties", {}).get("icon", "")
                content = str(block.get("content", "") or block.get("text", ""))
                if "yellow" in bg and "⚡" in icon and "velocity" in content.lower() and "180" in content:
                    velocity_callout_found = True
                    break
    
        if not velocity_callout_found:
            errors.append("[X] Yellow velocity callout with ⚡ icon not found")
        else:
            checks_passed.append("[C] Yellow velocity callout with ⚡ icon found")
    
        # Check for Sprint Goals heading_3 and count numbered items
        goals_found = False
        goals_idx = None
        for i in range(commitment_idx, len(all_blocks)):
            block = all_blocks[i]
            if block.get("type") in ["heading2", "heading_2"]:
                if i > commitment_idx:
                    break
            if block.get("type") in ["heading3", "heading_3"]:
                content = str(block.get("content", "") or block.get("text", ""))
                if "Sprint Goals" in content and "🎯" in content:
                    goals_found = True
                    goals_idx = i
                    break
    
        if not goals_found:
            errors.append("[X] '🎯 Sprint Goals' heading_3 not found")
        else:
            checks_passed.append("[C] '🎯 Sprint Goals' heading_3 found")
    
        # Count numbered list items after Sprint Goals heading
        numbered_goals = 0
        for i in range(goals_idx + 1, min(goals_idx + 10, len(all_blocks))):
            block = all_blocks[i]
            if block.get("type") in ["heading2", "heading_2", "heading3", "heading_3"]:
                break
            if block.get("type") == "numberedList":
                numbered_goals += 1
    
        if numbered_goals < 3:
            errors.append(f"[X] Found {numbered_goals} sprint goals, expected 3")
        else:
            checks_passed.append(f"[C] Found {numbered_goals} sprint goals, expected 3")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

    # -----------------------------------------------------------------------------
    # add-engineering-wiki-quick-start-v2
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_add_engineering_wiki_quick_start(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Task: Add Quick Start Guide section at top of Engineering Wiki.
    
    Validates:
    1. Quick Start heading_2 near top
    2. Blue callout with quick start message
    3. Four heading_3 sections with number emojis
    4. Todos under each section
    5. Divider and bold time estimate at end
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    # Find Engineering Wiki page
    try:
        wiki_results = final_state_backend.query({
            "collection": "pages",
            "filter": {"title": "Engineering Wiki"}
        })
    
        if not wiki_results:
            errors.append("[X] Engineering Wiki page not found")
        else:
            checks_passed.append("[C] Engineering Wiki page found")
    
        wiki = wiki_results[0]
        # Query blocks collection for this page
        all_blocks = final_state_backend.query({
            "collection": "blocks",
            "filter": {"pageId": wiki.get("_id")}
        })
    
        # Find Quick Start heading
        quickstart_idx = None
        for i, block in enumerate(all_blocks):
            if block.get("type") in ["heading2", "heading_2"]:
                content = str(block.get("content", "") or block.get("text", ""))
                if "Quick Start for New Engineers" in content and "🚀" in content:
                    quickstart_idx = i
                    break
    
        if quickstart_idx is None:
            errors.append("[X] '🚀 Quick Start for New Engineers' heading not found")
        else:
            checks_passed.append("[C] '🚀 Quick Start for New Engineers' heading found")
    
        # Should be near top (within first 5 blocks)
        if quickstart_idx > 4:
            errors.append(f"[X] Quick Start should be at top, found at index {quickstart_idx}")
        else:
            checks_passed.append(f"[C] Quick Start should be at top, found at index {quickstart_idx}")
    
        # Check for blue callout
        callout_found = False
        for i in range(quickstart_idx + 1, min(quickstart_idx + 3, len(all_blocks))):
            block = all_blocks[i]
            if block.get("type") == "callout":
                bg = block.get("properties", {}).get("backgroundColor", "")
                icon = block.get("properties", {}).get("icon", "")
                if "blue" in bg and "📘" in icon:
                    callout_found = True
                    break
    
        if not callout_found:
            errors.append("[X] Blue callout with book icon not found")
        else:
            checks_passed.append("[C] Blue callout with book icon found")
    
        # Check for four heading_3 sections with number emojis
        numbered_h3 = []
        for i in range(quickstart_idx, len(all_blocks)):
            block = all_blocks[i]
            if block.get("type") in ["heading2", "heading_2"]:
                if i > quickstart_idx:
                    break
            if block.get("type") in ["heading3", "heading_3"]:
                content = str(block.get("content", "") or block.get("text", ""))
                if any(emoji in content for emoji in ["1️⃣", "2️⃣", "3️⃣", "4️⃣"]):
                    numbered_h3.append(content)
    
        if len(numbered_h3) < 4:
            errors.append(f"[X] Found {len(numbered_h3)} numbered heading_3 sections, expected 4")
        else:
            checks_passed.append(f"[C] Found {len(numbered_h3)} numbered heading_3 sections, expected 4")
    
        # Check for todos
        todo_count = 0
        for i in range(quickstart_idx, len(all_blocks)):
            block = all_blocks[i]
            if block.get("type") in ["heading2", "heading_2"]:
                if i > quickstart_idx:
                    break
            if block.get("type") == "todo":
                todo_count += 1
    
        if todo_count < 12:  # 3 todos per section × 4 sections
            errors.append(f"[X] Found {todo_count} todos, expected at least 12")
        else:
            checks_passed.append(f"[C] Found {todo_count} todos, expected at least 12")
    
        # Check for divider and time estimate
        divider_found = False
        time_estimate_found = False
    
        for i in range(quickstart_idx, len(all_blocks)):
            block = all_blocks[i]
            if block.get("type") in ["heading2", "heading_2"]:
                if i > quickstart_idx:
                    break
            if block.get("type") == "divider":
                divider_found = True
            if block.get("type") == "paragraph":
                content = str(block.get("content", "") or block.get("text", ""))
                if "Time to complete" in content and "2-3 days" in content:
                    time_estimate_found = True
    
        if not divider_found:
            errors.append("[X] Divider not found in Quick Start section")
        else:
            checks_passed.append("[C] Divider found in Quick Start section")
    
        if not time_estimate_found:
            errors.append("[X] Time estimate paragraph not found")
        else:
            checks_passed.append("[C] Time estimate paragraph found")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

    # -----------------------------------------------------------------------------
    # add-getting-started-time-estimates-v2
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_add_getting_started_time_estimates(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Task: Add Time Estimates section after Quick Start Checklist todos.
    
    Validates:
    1. Time Estimates heading_3 in correct position
    2. Four bulleted items with time estimates
    3. Blue pro tip callout with 💡 icon
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    # Find Getting Started page
    try:
        page_results = final_state_backend.query({
            "collection": "pages",
            "filter": {"title": "Getting Started"}
        })
    
        if not page_results:
            errors.append("[X] Getting Started page not found")
        else:
            checks_passed.append("[C] Getting Started page found")
    
        page = page_results[0]
        # Query blocks collection for this page
        all_blocks = final_state_backend.query({
            "collection": "blocks",
            "filter": {"pageId": page.get("_id")}
        })
    
        # Find Time Estimates heading
        time_estimates_idx = None
        for i, block in enumerate(all_blocks):
            if block.get("type") in ["heading3", "heading_3"]:
                content = str(block.get("content", "") or block.get("text", ""))
                if "Time Estimates" in content and "⏱️" in content:
                    time_estimates_idx = i
                    break
    
        if time_estimates_idx is None:
            errors.append("[X] '⏱️ Time Estimates' heading_3 not found")
        else:
            checks_passed.append("[C] '⏱️ Time Estimates' heading_3 found")
    
        # Check for four bulleted items with time estimates
        time_bullets = []
        for i in range(time_estimates_idx + 1, len(all_blocks)):
            block = all_blocks[i]
            if block.get("type") in ["heading2", "heading_2", "heading3", "heading_3"]:
                break
            if block.get("type") == "bulletedList":
                content = str(block.get("content", "") or block.get("text", ""))
                if "minutes" in content.lower():
                    time_bullets.append(content)
    
        if len(time_bullets) < 4:
            errors.append(f"[X] Found {len(time_bullets)} time estimate bullets, expected 4")
        else:
            checks_passed.append(f"[C] Found {len(time_bullets)} time estimate bullets, expected 4")
    
        # Check for specific time estimates
        required_times = ["15 minutes", "30 minutes", "45 minutes", "20 minutes"]
        found_times = 0
    
        for bullet in time_bullets:
            for req_time in required_times:
                if req_time in bullet:
                    found_times += 1
                    break
    
        if found_times < 4:
            errors.append(f"[X] Found {found_times} of 4 required time estimates")
        else:
            checks_passed.append(f"[C] Found {found_times} of 4 required time estimates")
    
        # Check for blue pro tip callout
        callout_found = False
        for i in range(time_estimates_idx, min(time_estimates_idx + 10, len(all_blocks))):
            block = all_blocks[i]
            if block.get("type") == "callout":
                bg = block.get("properties", {}).get("backgroundColor", "")
                icon = block.get("properties", {}).get("icon", "")
                content = str(block.get("content", "") or block.get("text", ""))
                if "blue" in bg and "💡" in icon and "Pro tip" in content:
                    callout_found = True
                    break
    
        if not callout_found:
            errors.append("[X] Blue pro tip callout with 💡 icon not found")
        else:
            checks_passed.append("[C] Blue pro tip callout with 💡 icon found")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

    # -----------------------------------------------------------------------------
    # add-team-retrospective-action-tracking-v2
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_add_team_retrospective_action_tracking(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Task: Add Retrospective Metrics section with action items.
    
    Validates:
    1. Retrospective Metrics heading_2 after What went well
    2. Markdown code block with team health scores
    3. Action Items heading_3 with three unchecked todos
    4. Purple callout with next retro date
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    # Find Team Retrospective page
    try:
        page_results = final_state_backend.query({
            "collection": "pages",
            "filter": {"title": "Team Retrospective"}
        })
    
        if not page_results:
            errors.append("[X] Team Retrospective page not found")
        else:
            checks_passed.append("[C] Team Retrospective page found")
    
        page = page_results[0]
        # Query blocks collection for this page
        all_blocks = final_state_backend.query({
            "collection": "blocks",
            "filter": {"pageId": page.get("_id")}
        })
    
        # Find Retrospective Metrics heading
        metrics_idx = None
        for i, block in enumerate(all_blocks):
            if block.get("type") in ["heading2", "heading_2"]:
                content = str(block.get("content", "") or block.get("text", ""))
                if "Retrospective Metrics" in content and "📊" in content:
                    metrics_idx = i
                    break
    
        if metrics_idx is None:
            errors.append("[X] '📊 Retrospective Metrics' heading not found")
        else:
            checks_passed.append("[C] '📊 Retrospective Metrics' heading found")
    
        # Check for markdown code block with scores
        code_found = False
        for i in range(metrics_idx + 1, min(metrics_idx + 5, len(all_blocks))):
            block = all_blocks[i]
            if block.get("type") == "code":
                lang = block.get("properties", {}).get("language", "")
                content = str(block.get("content", "") or block.get("text", ""))
                if "markdown" in lang.lower() and "Team Health Score" in content and "8.5/10" in content:
                    code_found = True
                    break
    
        if not code_found:
            errors.append("[X] Markdown code block with team health scores not found")
        else:
            checks_passed.append("[C] Markdown code block with team health scores found")
    
        # Find Action Items heading_3
        action_items_found = False
        for i in range(metrics_idx, len(all_blocks)):
            block = all_blocks[i]
            if block.get("type") in ["heading2", "heading_2"]:
                if i > metrics_idx:
                    break
            if block.get("type") in ["heading3", "heading_3"]:
                content = str(block.get("content", "") or block.get("text", ""))
                if "Action Items" in content and "🎯" in content:
                    action_items_found = True
                    break
    
        if not action_items_found:
            errors.append("[X] '🎯 Action Items from Previous Retro' heading not found")
        else:
            checks_passed.append("[C] '🎯 Action Items from Previous Retro' heading found")
    
        # Check for three unchecked todos
        required_actions = ["standup notes", "knowledge base", "1-on-1"]
        found_actions = 0
    
        for i in range(metrics_idx, len(all_blocks)):
            block = all_blocks[i]
            if block.get("type") in ["heading2", "heading_2"]:
                if i > metrics_idx:
                    break
            if block.get("type") == "todo" and not block.get("properties", {}).get("checked"):
                content = str(block.get("content", "") or block.get("text", "")).lower()
                for action in required_actions:
                    if action in content:
                        found_actions += 1
                        break
    
        if found_actions < 3:
            errors.append(f"[X] Found {found_actions} of 3 required action item todos")
        else:
            checks_passed.append(f"[C] Found {found_actions} of 3 required action item todos")
    
        # Check for purple callout with next retro date
        callout_found = False
        for i in range(metrics_idx, len(all_blocks)):
            block = all_blocks[i]
            if block.get("type") in ["heading2", "heading_2"]:
                if i > metrics_idx:
                    break
            if block.get("type") == "callout":
                bg = block.get("properties", {}).get("backgroundColor", "")
                icon = block.get("properties", {}).get("icon", "")
                content = str(block.get("content", "") or block.get("text", ""))
                if "purple" in bg and "📅" in icon and "Next retro" in content:
                    callout_found = True
                    break
    
        if not callout_found:
            errors.append("[X] Purple callout with next retro date not found")
        else:
            checks_passed.append("[C] Purple callout with next retro date found")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

    # -----------------------------------------------------------------------------
    # create-engineering-standards-child-v2
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_create_engineering_standards_child(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Task: Create Engineering Standards page extracting callouts by color.
    
    Validates:
    1. Page created as child of Engineering Wiki
    2. Extracted Guidelines heading_2
    3. Multiple heading_3 sections for different callout colors
    4. Guideline Statistics heading_2
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    # Find Engineering Wiki page
    try:
        wiki_results = final_state_backend.query({
            "collection": "pages",
            "filter": {"title": "Engineering Wiki"}
        })
    
        if not wiki_results:
            errors.append("[X] Engineering Wiki page not found")
        else:
            checks_passed.append("[C] Engineering Wiki page found")
    
        wiki = wiki_results[0]
        wiki_id = wiki.get("_id")
    
        # Find Engineering Standards child page
        standards_results = final_state_backend.query({
            "collection": "pages",
            "filter": {"parentId": wiki_id}
        })
    
        standards_page = None
        for page in standards_results:
            if "Engineering Standards" in page.get("title", ""):
                standards_page = page
                break
    
        if not standards_page:
            errors.append("[X] Engineering Standards page not found as child of Engineering Wiki")
        else:
            checks_passed.append("[C] Engineering Standards page found as child of Engineering Wiki")
    
        # Query blocks collection for this page
        all_blocks = final_state_backend.query({
            "collection": "blocks",
            "filter": {"pageId": standards_page.get("_id")}
        })
    
        # Check for heading_1
        if not all_blocks or all_blocks[0].get("type") not in ["heading1", "heading_1"]:
            errors.append("[X] Page should start with heading_1")
        else:
            checks_passed.append("[C] Page should start with heading_1")
    
        # Find Extracted Guidelines heading
        extracted_found = False
        for block in all_blocks:
            if block.get("type") in ["heading2", "heading_2"]:
                content = str(block.get("content", "") or block.get("text", ""))
                if "Extracted Guidelines" in content and "📋" in content:
                    extracted_found = True
                    break
    
        if not extracted_found:
            errors.append("[X] '📋 Extracted Guidelines' heading not found")
        else:
            checks_passed.append("[C] '📋 Extracted Guidelines' heading found")
    
        # Check for color category heading_3 sections
        color_categories = ["Tips", "Warnings", "Critical", "Best Practices", "Notes", "Security"]
        found_categories = 0
    
        for block in all_blocks:
            if block.get("type") in ["heading3", "heading_3"]:
                content = str(block.get("content", "") or block.get("text", ""))
                for category in color_categories:
                    if category in content:
                        found_categories += 1
                        break
    
        if found_categories < 3:
            errors.append(f"[X] Found {found_categories} color category sections, expected at least 3")
        else:
            checks_passed.append(f"[C] Found {found_categories} color category sections, expected at least 3")
    
        # Check for Guideline Statistics heading
        statistics_found = False
        for block in all_blocks:
            if block.get("type") in ["heading2", "heading_2"]:
                content = str(block.get("content", "") or block.get("text", ""))
                if "Guideline Statistics" in content and "📊" in content:
                    statistics_found = True
                    break
    
        if not statistics_found:
            errors.append("[X] '📊 Guideline Statistics' heading not found")
        else:
            checks_passed.append("[C] '📊 Guideline Statistics' heading found")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

    # -----------------------------------------------------------------------------
    # reorganize-engineering-wiki-sections-swap-v2
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_reorganize_engineering_wiki_sections_swap(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Task: Rotate Engineering Wiki heading_2 sections and add changelog.
    
    Validates:
    1. Sections rotated (last becomes first)
    2. Wiki Changelog heading_2 at end
    3. Paragraph with reorganization date
    4. Unchecked todo about table of contents
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    # Find Engineering Wiki page
    try:
        wiki_results = final_state_backend.query({
            "collection": "pages",
            "filter": {"title": "Engineering Wiki"}
        })
    
        if not wiki_results:
            errors.append("[X] Engineering Wiki page not found")
        else:
            checks_passed.append("[C] Engineering Wiki page found")
    
        wiki = wiki_results[0]
        # Query blocks collection for this page
        all_blocks = final_state_backend.query({
            "collection": "blocks",
            "filter": {"pageId": wiki.get("_id")}
        })
    
        # Find all heading_2 sections
        h2_indices = []
        for i, block in enumerate(all_blocks):
            if block.get("type") in ["heading2", "heading_2"]:
                content = str(block.get("content", "") or block.get("text", ""))
                h2_indices.append((i, content))
    
        if len(h2_indices) < 3:
            errors.append(f"[X] Found {len(h2_indices)} heading_2 sections, need at least 3 to verify rotation")
        else:
            checks_passed.append(f"[C] Found {len(h2_indices)} heading_2 sections, need at least 3 to verify rotation")
    
        # Find Wiki Changelog section (should be at end)
        changelog_found = False
        changelog_idx = None
        for i, content in h2_indices:
            if "Wiki Changelog" in content and "📝" in content:
                changelog_found = True
                changelog_idx = i
                break
    
        if not changelog_found:
            errors.append("[X] '📝 Wiki Changelog' heading not found")
        else:
            checks_passed.append("[C] '📝 Wiki Changelog' heading found")
    
        # Changelog should be last or near last heading_2
        if changelog_idx != h2_indices[-1][0]:
            # Allow it to be second-to-last as well
            if len(h2_indices) > 1 and changelog_idx != h2_indices[-2][0]:
                errors.append("[X] Wiki Changelog should be at the end")
            else:
                checks_passed.append("[C] Wiki Changelog should be at the end")
    
        # Check for reorganization paragraph
        reorg_paragraph_found = False
        for i in range(changelog_idx, len(all_blocks)):
            block = all_blocks[i]
            if block.get("type") == "paragraph":
                content = str(block.get("content", "") or block.get("text", ""))
                if "Last reorganized" in content and "Sections reordered" in content:
                    reorg_paragraph_found = True
                    break
    
        if not reorg_paragraph_found:
            errors.append("[X] Reorganization paragraph not found in Wiki Changelog")
        else:
            checks_passed.append("[C] Reorganization paragraph found in Wiki Changelog")
    
        # Check for unchecked todo about table of contents
        todo_found = False
        for i in range(changelog_idx, len(all_blocks)):
            block = all_blocks[i]
            if block.get("type") == "todo" and not block.get("properties", {}).get("checked"):
                content = str(block.get("content", "") or block.get("text", ""))
                if "table of contents" in content.lower():
                    todo_found = True
                    break
    
        if not todo_found:
            errors.append("[X] Unchecked todo about table of contents not found")
        else:
            checks_passed.append("[C] Unchecked todo about table of contents found")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

    # -----------------------------------------------------------------------------
    # add-engineering-wiki-tool-integration-v2
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_add_engineering_wiki_tool_integration(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Task: Add Development Tools section with bookmark resources.
    
    Validates:
    1. Development Tools & Integration heading_2
    2. Introductory paragraph about essential tools
    3. Core Development Stack heading_3 with three bookmarks and captions
    4. Monitoring & Analytics heading_3 with two bookmarks and captions
    5. Divider between sections
    6. Yellow pro tip callout with 💡 icon
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    # Find Engineering Wiki page
    try:
        wiki_results = final_state_backend.query({
            "collection": "pages",
            "filter": {"title": "Engineering Wiki"}
        })
    
        if not wiki_results:
            errors.append("[X] Engineering Wiki page not found")
        else:
            checks_passed.append("[C] Engineering Wiki page found")
    
        wiki = wiki_results[0]
        # Query blocks collection for this page
        all_blocks = final_state_backend.query({
            "collection": "blocks",
            "filter": {"pageId": wiki.get("_id")}
        })
    
        # Find Development Tools heading
        tools_idx = None
        for i, block in enumerate(all_blocks):
            if block.get("type") in ["heading2", "heading_2"]:
                content = str(block.get("content", "") or block.get("text", ""))
                if "Development Tools" in content and "Integration" in content and "🔧" in content:
                    tools_idx = i
                    break
    
        if tools_idx is None:
            errors.append("[X] '🔧 Development Tools & Integration' heading not found")
        else:
            checks_passed.append("[C] '🔧 Development Tools & Integration' heading found")
    
        # Check for introductory paragraph after heading
        intro_paragraph_found = False
        for i in range(tools_idx + 1, min(tools_idx + 3, len(all_blocks))):
            block = all_blocks[i]
            if block.get("type") == "paragraph":
                content = str(block.get("content", "") or block.get("text", ""))
                if "Essential tools" in content and "engineering workflow" in content:
                    intro_paragraph_found = True
                    break
    
        if not intro_paragraph_found:
            errors.append("[X] Introductory paragraph 'Essential tools for our engineering workflow.' not found")
        else:
            checks_passed.append("[C] Introductory paragraph 'Essential tools for our engineering workflow.' found")
    
        # Find Core Development Stack heading_3
        core_stack_found = False
        core_stack_idx = None
        for i in range(tools_idx, len(all_blocks)):
            block = all_blocks[i]
            if block.get("type") in ["heading2", "heading_2"]:
                if i > tools_idx:
                    break
            if block.get("type") in ["heading3", "heading_3"]:
                content = str(block.get("content", "") or block.get("text", ""))
                if "Core Development Stack" in content and "🛠️" in content:
                    core_stack_found = True
                    core_stack_idx = i
                    break
    
        if not core_stack_found:
            errors.append("[X] '🛠️ Core Development Stack' heading_3 not found")
        else:
            checks_passed.append("[C] '🛠️ Core Development Stack' heading_3 found")
    
        # Find Monitoring & Analytics heading_3
        monitoring_found = False
        monitoring_idx = None
        for i in range(tools_idx, len(all_blocks)):
            block = all_blocks[i]
            if block.get("type") in ["heading2", "heading_2"]:
                if i > tools_idx:
                    break
            if block.get("type") in ["heading3", "heading_3"]:
                content = str(block.get("content", "") or block.get("text", ""))
                if "Monitoring" in content and "Analytics" in content and "📊" in content:
                    monitoring_found = True
                    monitoring_idx = i
                    break
    
        if not monitoring_found:
            errors.append("[X] '📊 Monitoring & Analytics' heading_3 not found")
        else:
            checks_passed.append("[C] '📊 Monitoring & Analytics' heading_3 found")
    
        # Check for bookmarks under Core Development Stack (3 expected)
        core_bookmarks = []
        core_bookmark_blocks = []
        required_core_urls = ["github.com", "notion.so", "figma.com"]
        required_core_captions = [
            ("github", "version control"),
            ("notion", "documentation"),
            ("figma", "design")
        ]
    
        if core_stack_idx and monitoring_idx:
            for i in range(core_stack_idx, monitoring_idx):
                block = all_blocks[i]
                if block.get("type") == "bookmark":
                    url = str(block.get("properties", {}).get("url", "") or block.get("content", ""))
                    core_bookmarks.append(url)
                    core_bookmark_blocks.append(block)
    
        core_found = sum(1 for url in core_bookmarks if any(req in url.lower() for req in required_core_urls))
    
        if core_found < 3:
            errors.append(f"[X] Found {core_found} of 3 required Core Development Stack bookmarks")
        else:
            checks_passed.append(f"[C] Found {core_found} of 3 required Core Development Stack bookmarks")
    
        # Check bookmark captions
        captions_found = 0
        for block in core_bookmark_blocks:
            caption = str(block.get("properties", {}).get("caption", "")).lower()
            for url_keyword, caption_keyword in required_core_captions:
                url = str(block.get("properties", {}).get("url", "") or block.get("content", "")).lower()
                if url_keyword in url and caption_keyword in caption:
                    captions_found += 1
                    break
    
        if captions_found < 3:
            errors.append(f"[X] Found {captions_found} of 3 Core Development Stack bookmarks with proper captions")
        else:
            checks_passed.append(f"[C] Found {captions_found} of 3 Core Development Stack bookmarks with proper captions")
    
        # Check for bookmarks under Monitoring & Analytics (2 expected)
        monitoring_bookmarks = []
        monitoring_bookmark_blocks = []
        required_monitoring_urls = ["datadoghq.com", "sentry.io"]
        required_monitoring_captions = [
            ("datadog", "monitoring"),
            ("sentry", "error")
        ]
    
        for i in range(monitoring_idx, len(all_blocks)):
            block = all_blocks[i]
            if block.get("type") in ["heading2", "heading_2", "heading3", "heading_3"]:
                if i > monitoring_idx:
                    break
            if block.get("type") == "bookmark":
                url = str(block.get("properties", {}).get("url", "") or block.get("content", ""))
                monitoring_bookmarks.append(url)
                monitoring_bookmark_blocks.append(block)
    
        monitoring_found_count = sum(1 for url in monitoring_bookmarks if any(req in url.lower() for req in required_monitoring_urls))
    
        if monitoring_found_count < 2:
            errors.append(f"[X] Found {monitoring_found_count} of 2 required Monitoring & Analytics bookmarks")
        else:
            checks_passed.append(f"[C] Found {monitoring_found_count} of 2 required Monitoring & Analytics bookmarks")
    
        # Check bookmark captions
        monitoring_captions_found = 0
        for block in monitoring_bookmark_blocks:
            caption = str(block.get("properties", {}).get("caption", "")).lower()
            for url_keyword, caption_keyword in required_monitoring_captions:
                url = str(block.get("properties", {}).get("url", "") or block.get("content", "")).lower()
                if url_keyword in url and caption_keyword in caption:
                    monitoring_captions_found += 1
                    break
    
        if monitoring_captions_found < 2:
            errors.append(f"[X] Found {monitoring_captions_found} of 2 Monitoring & Analytics bookmarks with proper captions")
        else:
            checks_passed.append(f"[C] Found {monitoring_captions_found} of 2 Monitoring & Analytics bookmarks with proper captions")
    
        # Check for divider between sections
        divider_found = False
        if core_stack_idx and monitoring_idx:
            for i in range(core_stack_idx, monitoring_idx):
                if all_blocks[i].get("type") == "divider":
                    divider_found = True
                    break
    
        if not divider_found:
            errors.append("[X] Divider not found between Core Development Stack and Monitoring sections")
        else:
            checks_passed.append("[C] Divider found between Core Development Stack and Monitoring sections")
    
        # Check for yellow pro tip callout
        callout_found = False
        for i in range(tools_idx, len(all_blocks)):
            block = all_blocks[i]
            if block.get("type") in ["heading2", "heading_2"]:
                if i > tools_idx:
                    break
            if block.get("type") == "callout":
                bg = block.get("properties", {}).get("backgroundColor", "")
                icon = block.get("properties", {}).get("icon", "")
                content = str(block.get("content", "") or block.get("text", ""))
                if "yellow" in bg and "💡" in icon and "Pro tip" in content and "browser extensions" in content.lower():
                    callout_found = True
                    break
    
        if not callout_found:
            errors.append("[X] Yellow pro tip callout not found")
        else:
            checks_passed.append("[C] Yellow pro tip callout found")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# New Task Reward Functions - Batch 28
# =============================================================================

# -----------------------------------------------------------------------------
# add-weekly-standup-next-week-priorities-v2
# -----------------------------------------------------------------------------
def _validate_agent_add_weekly_standup_next_week_priorities(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Task: Add Next Week Priorities section with 4 todos, Blockers section with callout,
    quote with completed task count, and duplicate page.
    
    Validates:
    1. "🎯 Next Week Priorities" heading_2 after existing todos
    2. 4 unchecked todos with exact text
    3. "🚧 Blockers" heading_2 with red callout (no icon)
    4. Quote block with accurate completed task count
    5. Duplicate page with current week dates in title
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    # 1. Find Weekly Standup Template page
    try:
        page_results = final_state_backend.query({
            "collection": "pages",
            "filter": {"title": "Weekly Standup Template"}
        })
    
        if not page_results:
            errors.append("[X] Weekly Standup Template page not found")
        else:
            checks_passed.append("[C] Weekly Standup Template page found")
    
        page = page_results[0]
        # Query blocks collection for this page
        all_blocks = final_state_backend.query({
            "collection": "blocks",
            "filter": {"pageId": page.get("_id")}
        })
    
        # 2. Check for heading_2 "🎯 Next Week Priorities"
        next_week_idx = None
        for i, block in enumerate(all_blocks):
            if block.get("type") in ["heading2", "heading_2"]:
                content = str(block.get("content", "") or block.get("text", ""))
                if "🎯" in content and "Next Week Priorities" in content:
                    next_week_idx = i
                    break
    
        if next_week_idx is None:
            errors.append("[X] '🎯 Next Week Priorities' heading not found")
        else:
            checks_passed.append("[C] '🎯 Next Week Priorities' heading found")
    
        # 3. Verify 4 unchecked todos with exact text
        expected_todos = [
            "🔍 Research new framework options",
            "📊 Prepare performance metrics report",
            "🤝 Collaborate on API design document",
            "🚀 Deploy feature to staging"
        ]
    
        found_todos = []
        for i in range(next_week_idx + 1, min(next_week_idx + 10, len(all_blocks))):
            if all_blocks[i].get("type") == "todo":
                content = str(all_blocks[i].get("content", "") or all_blocks[i].get("text", ""))
                checked = all_blocks[i].get("properties", {}).get("checked", False)
                if not checked:
                    found_todos.append(content)
    
        matching_todos = 0
        for expected in expected_todos:
            if any(expected in found for found in found_todos):
                matching_todos += 1
    
        if matching_todos < 4:
            errors.append(f"[X] Found {matching_todos} of 4 expected unchecked todos")
        else:
            checks_passed.append(f"[C] Found {matching_todos} of 4 expected unchecked todos")
    
        # 4. Check for heading_2 "🚧 Blockers"
        blockers_idx = None
        for i, block in enumerate(all_blocks):
            if block.get("type") in ["heading2", "heading_2"]:
                content = str(block.get("content", "") or block.get("text", ""))
                if "🚧" in content and "Blockers" in content:
                    blockers_idx = i
                    break
    
        if blockers_idx is None:
            errors.append("[X] '🚧 Blockers' heading not found")
        else:
            checks_passed.append("[C] '🚧 Blockers' heading found")
    
        # 5. Verify red callout after Blockers
        red_callout_found = False
        for i in range(blockers_idx + 1, min(blockers_idx + 5, len(all_blocks))):
            if all_blocks[i].get("type") == "callout":
                bg = all_blocks[i].get("properties", {}).get("backgroundColor", "")
                content = str(all_blocks[i].get("content", "") or all_blocks[i].get("text", ""))
                if "red" in bg.lower() and "impediments" in content.lower():
                    red_callout_found = True
                    break
    
        if not red_callout_found:
            errors.append("[X] Red callout not found after Blockers heading")
        else:
            checks_passed.append("[C] Red callout found after Blockers heading")
    
        # 6. Count checked todos and verify quote block
        checked_count = sum(1 for block in all_blocks 
                           if block.get("type") == "todo" 
                           and block.get("properties", {}).get("checked", False))
    
        quote_found = False
        for block in all_blocks:
            if block.get("type") == "quote":
                content = str(block.get("content", "") or block.get("text", ""))
                if "Progress this week" in content and "tasks completed" in content:
                    # Check if the number matches
                    if str(checked_count) in content:
                        quote_found = True
                        break
    
        if not quote_found:
            errors.append("[X] Quote block with accurate completed task count not found")
        else:
            checks_passed.append("[C] Quote block with accurate completed task count found")
    
        # 7. Check for duplicate page
        # Use regex to find pages with "Weekly Standup -" in title (avoids text index timing issues)
        all_pages = final_state_backend.query({
            "collection": "pages",
            "filter": {"title": {"$regex": "Weekly Standup -"}}
        })
        duplicate_found = False
        for p in all_pages:
            title = p.get("title", "")
            if "Weekly Standup -" in title and title != "Weekly Standup Template":
                duplicate_found = True
                break
    
        if not duplicate_found:
            errors.append("[X] Duplicate page with current week dates not found")
        else:
            checks_passed.append("[C] Duplicate page with current week dates found")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

    # -----------------------------------------------------------------------------
    # add-engineering-wiki-api-versioning-v2
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_add_engineering_wiki_api_versioning(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Task: Add comprehensive API versioning section.
    
    Validates:
    1. "🔄 API Versioning Strategy" heading_2 after existing content
    2. Paragraph about semantic versioning
    3. Numbered list with 3 items (MAJOR, MINOR, PATCH)
    4. Red callout with ⚠️ icon
    5. JavaScript code block with API_VERSION object
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    # 1. Find Engineering Wiki page
    try:
        page_results = final_state_backend.query({
            "collection": "pages",
            "filter": {"title": "Engineering Wiki"}
        })
    
        if not page_results:
            errors.append("[X] Engineering Wiki page not found")
        else:
            checks_passed.append("[C] Engineering Wiki page found")
    
        page = page_results[0]
        # Query blocks collection for this page
        all_blocks = final_state_backend.query({
            "collection": "blocks",
            "filter": {"pageId": page.get("_id")}
        })
    
        # 2. Check for heading_2 "🔄 API Versioning Strategy"
        versioning_idx = None
        for i, block in enumerate(all_blocks):
            if block.get("type") in ["heading2", "heading_2"]:
                content = str(block.get("content", "") or block.get("text", ""))
                if "🔄" in content and "API Versioning Strategy" in content:
                    versioning_idx = i
                    break
    
        if versioning_idx is None:
            errors.append("[X] '🔄 API Versioning Strategy' heading not found")
        else:
            checks_passed.append("[C] '🔄 API Versioning Strategy' heading found")
    
        # 3. Verify paragraph about semantic versioning
        paragraph_found = False
        for i in range(versioning_idx + 1, min(versioning_idx + 5, len(all_blocks))):
            if all_blocks[i].get("type") == "paragraph":
                content = str(all_blocks[i].get("content", "") or all_blocks[i].get("text", ""))
                if "semantic versioning" in content and "MAJOR.MINOR.PATCH" in content:
                    paragraph_found = True
                    break
    
        if not paragraph_found:
            errors.append("[X] Paragraph about semantic versioning not found")
        else:
            checks_passed.append("[C] Paragraph about semantic versioning found")
    
        # 4. Check numbered list with 3 items
        numbered_items = []
        for i in range(versioning_idx + 1, min(versioning_idx + 15, len(all_blocks))):
            block = all_blocks[i]
            if block.get("type") in ["numbered_list_item", "numberedListItem", "numbered_list", "numberedList"]:
                content = str(block.get("content", "") or block.get("text", ""))
                numbered_items.append(content)
    
        if len(numbered_items) < 3:
            errors.append(f"[X] Expected 3 numbered list items, found {len(numbered_items)}")
        else:
            checks_passed.append(f"[C] Found 3 numbered list items as expected")
    
        # Check for MAJOR, MINOR, PATCH mentions
        has_major = any("MAJOR" in item for item in numbered_items)
        has_minor = any("MINOR" in item for item in numbered_items)
        has_patch = any("PATCH" in item for item in numbered_items)
    
        if not (has_major and has_minor and has_patch):
            errors.append("[X] Numbered list missing MAJOR, MINOR, or PATCH version descriptions")
        else:
            checks_passed.append("[C] Numbered list has MAJOR, MINOR, or PATCH version descriptions")
    
        # 5. Verify red callout with ⚠️ icon
        red_callout_found = False
        for i in range(versioning_idx, min(versioning_idx + 20, len(all_blocks))):
            if all_blocks[i].get("type") == "callout":
                bg = all_blocks[i].get("properties", {}).get("backgroundColor", "")
                icon = all_blocks[i].get("properties", {}).get("icon", "")
                content = str(all_blocks[i].get("content", "") or all_blocks[i].get("text", ""))
                if "red" in bg.lower() and "⚠" in icon and "deprecation" in content.lower():
                    red_callout_found = True
                    break
    
        if not red_callout_found:
            errors.append("[X] Red callout with ⚠️ icon about deprecation not found")
        else:
            checks_passed.append("[C] Red callout with ⚠️ icon about deprecation found")
    
        # 6. Check JavaScript code block
        code_found = False
        for i in range(versioning_idx, min(versioning_idx + 25, len(all_blocks))):
            if all_blocks[i].get("type") == "code":
                lang = all_blocks[i].get("properties", {}).get("language", "")
                content = str(all_blocks[i].get("content", "") or all_blocks[i].get("text", ""))
                if "javascript" in lang.lower() and "API_VERSION" in content:
                    code_found = True
                    break
    
        if not code_found:
            errors.append("[X] JavaScript code block with API_VERSION not found")
        else:
            checks_passed.append("[C] JavaScript code block with API_VERSION found")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

    # -----------------------------------------------------------------------------
    # create-roadmap-summary-2024-v2
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_create_roadmap_summary_2024(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Task: Create Roadmap Summary 2024 as sibling of Project Roadmap.
    
    Validates:
    1. "Roadmap Summary 2024" exists as sibling with 🎯 icon
    2. Heading structure with Executive Summary
    3. Quarterly sections with todo counts
    4. Annual Metrics with correct total
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    # 1. Find Project Roadmap page
    try:
        roadmap_results = final_state_backend.query({
            "collection": "pages",
            "filter": {"title": "Project Roadmap"}
        })
    
        if not roadmap_results:
            errors.append("[X] Project Roadmap page not found")
        else:
            checks_passed.append("[C] Project Roadmap page found")
    
        roadmap_page = roadmap_results[0]
        roadmap_parent_id = roadmap_page.get("parentId")
    
        # 2. Check "Roadmap Summary 2024" exists as sibling
        summary_results = final_state_backend.query({
            "collection": "pages",
            "filter": {"title": "Roadmap Summary 2024"}
        })
    
        if not summary_results:
            errors.append("[X] 'Roadmap Summary 2024' page not found")
        else:
            checks_passed.append("[C] 'Roadmap Summary 2024' page found")
    
        summary_page = summary_results[0]
    
        # Verify it's a sibling (same parent)
        if summary_page.get("parentId") != roadmap_parent_id:
            errors.append("[X] Roadmap Summary 2024 is not a sibling of Project Roadmap")
        else:
            checks_passed.append("[C] Roadmap Summary 2024 is a sibling of Project Roadmap")
    
        # Check icon
        if summary_page.get("icon") != "🎯":
            errors.append("[X] Roadmap Summary 2024 does not have 🎯 icon")
        else:
            checks_passed.append("[C] Roadmap Summary 2024 has 🎯 icon")
    
        # Query blocks collection for the summary page
        all_blocks = final_state_backend.query({
            "collection": "blocks",
            "filter": {"pageId": summary_page.get("_id")}
        })
    
        # 3. Check heading_1 "📊 2024 Roadmap Consolidated View"
        h1_found = False
        for block in all_blocks:
            if block.get("type") in ["heading1", "heading_1"]:
                content = str(block.get("content", "") or block.get("text", ""))
                if "📊" in content and "2024 Roadmap Consolidated View" in content:
                    h1_found = True
                    break
    
        if not h1_found:
            errors.append("[X] '📊 2024 Roadmap Consolidated View' heading_1 not found")
        else:
            checks_passed.append("[C] '📊 2024 Roadmap Consolidated View' heading_1 found")
    
        # 4. Check heading_2 "🔍 Executive Summary"
        exec_summary_found = False
        for block in all_blocks:
            if block.get("type") in ["heading2", "heading_2"]:
                content = str(block.get("content", "") or block.get("text", ""))
                if "🔍" in content and "Executive Summary" in content:
                    exec_summary_found = True
                    break
    
        if not exec_summary_found:
            errors.append("[X] '🔍 Executive Summary' heading_2 not found")
        else:
            checks_passed.append("[C] '🔍 Executive Summary' heading_2 found")
    
        # 5. Find quarterly goal pages (filter at query level for "Goals" or "Q" in title)
        quarterly_pages = final_state_backend.query({
            "collection": "pages",
            "filter": {
                "parentId": roadmap_page.get("_id"),
                "$or": [
                    {"title": {"$regex": "Goals", "$options": "i"}},
                    {"title": {"$regex": "Q", "$options": "i"}}
                ]
            }
        })
    
        if not isinstance(quarterly_pages, list):
            quarterly_pages = []
    
        if len(quarterly_pages) == 0:
            errors.append("[X] No quarterly goal pages found")
        else:
            checks_passed.append("[C] quarterly goal pages found")
    
        # 6. Count total todos from all quarterly pages
        total_todos = 0
        for q_page in quarterly_pages:
            # Query blocks collection for this page
            q_blocks = final_state_backend.query({
                "collection": "blocks",
                "filter": {"pageId": q_page.get("_id")}
            })
            todo_count = sum(1 for block in q_blocks if block.get("type") == "todo")
            total_todos += todo_count
    
        # 7. Check for Annual Metrics section
        annual_metrics_found = False
        for block in all_blocks:
            if block.get("type") in ["heading2", "heading_2"]:
                content = str(block.get("content", "") or block.get("text", ""))
                if "📈" in content and "Annual Metrics" in content:
                    annual_metrics_found = True
                    break
    
        if not annual_metrics_found:
            errors.append("[X] '📈 Annual Metrics' heading_2 not found")
        else:
            checks_passed.append("[C] '📈 Annual Metrics' heading_2 found")
    
        # 8. Verify total in paragraph
        total_found = False
        for block in all_blocks:
            if block.get("type") == "paragraph":
                content = str(block.get("content", "") or block.get("text", ""))
                if "Total objectives" in content and str(total_todos) in content:
                    total_found = True
                    break
    
        if not total_found:
            errors.append(f"[X] Total objectives paragraph with correct count ({total_todos}) not found")
        else:
            checks_passed.append(f"[C] Total objectives paragraph with correct count ({total_todos}) found")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

    # -----------------------------------------------------------------------------
    # add-sprint-planning-metrics-analysis-v2
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_add_sprint_planning_metrics_analysis(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Task: Analyze Sprint Planning page and insert Sprint Metrics section.
    
    Validates:
    1. Counts attendees, goals, action items
    2. "📊 Sprint Metrics" heading_2 after Action Items
    3. Bookmark block with correct URL/caption
    4. Bulleted list with calculated metrics
    5. Blue callout with completion statistics
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    # 1. Find Sprint Planning - Jan 15 page
    try:
        page_results = final_state_backend.query({
            "collection": "pages",
            "filter": {"title": "Sprint Planning - Jan 15"}
        })
    
        if not page_results:
            errors.append("[X] Sprint Planning - Jan 15 page not found")
        else:
            checks_passed.append("[C] Sprint Planning - Jan 15 page found")
    
        page = page_results[0]
        # Query blocks collection for this page
        all_blocks = final_state_backend.query({
            "collection": "blocks",
            "filter": {"pageId": page.get("_id")}
        })
    
        # 2. Count attendees (bulleted items under Attendees)
        attendee_count = 0
        in_attendees = False
        for block in all_blocks:
            if block.get("type") in ["heading2", "heading_2", "heading3", "heading_3"]:
                content = str(block.get("content", "") or block.get("text", ""))
                if "Attendees" in content:
                    in_attendees = True
                elif in_attendees:
                    in_attendees = False
            elif in_attendees and block.get("type") in ["bulleted_list_item", "bulletedListItem", "bulletedList"]:
                attendee_count += 1
    
        # 3. Count goals (numbered items under Sprint Goals)
        goal_count = 0
        in_goals = False
        for block in all_blocks:
            if block.get("type") in ["heading2", "heading_2", "heading3", "heading_3"]:
                content = str(block.get("content", "") or block.get("text", ""))
                if "Sprint Goals" in content:
                    in_goals = True
                elif in_goals:
                    in_goals = False
            elif in_goals and block.get("type") in ["numbered_list_item", "numberedListItem", "numberedList"]:
                goal_count += 1
    
        # 4. Count action items (todos under Action Items)
        action_count = 0
        checked_count = 0
        in_actions = False
        for block in all_blocks:
            if block.get("type") in ["heading2", "heading_2", "heading3", "heading_3"]:
                content = str(block.get("content", "") or block.get("text", ""))
                if "Action Items" in content:
                    in_actions = True
                elif in_actions:
                    in_actions = False
            elif in_actions and block.get("type") == "todo":
                action_count += 1
                if block.get("properties", {}).get("checked", False):
                    checked_count += 1
    
        completion_percentage = int((checked_count / action_count * 100) if action_count > 0 else 0)
    
        # 5. Check for heading_2 "📊 Sprint Metrics"
        metrics_idx = None
        for i, block in enumerate(all_blocks):
            if block.get("type") in ["heading2", "heading_2"]:
                content = str(block.get("content", "") or block.get("text", ""))
                if "📊" in content and "Sprint Metrics" in content:
                    metrics_idx = i
                    break
    
        if metrics_idx is None:
            errors.append("[X] '📊 Sprint Metrics' heading not found")
        else:
            checks_passed.append("[C] '📊 Sprint Metrics' heading found")
    
        # 6. Verify bookmark block
        bookmark_found = False
        for i in range(metrics_idx + 1, min(metrics_idx + 10, len(all_blocks))):
            if all_blocks[i].get("type") == "bookmark":
                url = str(all_blocks[i].get("properties", {}).get("url", ""))
                caption = str(all_blocks[i].get("properties", {}).get("caption", ""))
                if "metrics.example.com/sprint-jan-15" in url and "Live Sprint Dashboard" in caption:
                    bookmark_found = True
                    break
    
        if not bookmark_found:
            errors.append("[X] Bookmark with correct URL and caption not found")
        else:
            checks_passed.append("[C] Bookmark with correct URL and caption found")
    
        # 7. Check bulleted list with metrics
        metrics_found = {"team": False, "goals": False, "actions": False, "completion": False}
        for i in range(metrics_idx, min(metrics_idx + 20, len(all_blocks))):
            if all_blocks[i].get("type") in ["bulleted_list_item", "bulletedListItem", "bulletedList"]:
                content = str(all_blocks[i].get("content", "") or all_blocks[i].get("text", ""))
                if "Team size" in content and str(attendee_count) in content:
                    metrics_found["team"] = True
                if "Sprint goals" in content and str(goal_count) in content:
                    metrics_found["goals"] = True
                if "Action items" in content and str(action_count) in content:
                    metrics_found["actions"] = True
                if "Completion rate" in content and str(completion_percentage) in content:
                    metrics_found["completion"] = True
    
        if not all(metrics_found.values()):
            missing = [k for k, v in metrics_found.items() if not v]
            errors.append(f"[X] Missing metrics in bulleted list: {', '.join(missing)}")
        else:
            checks_passed.append(f"[C] has metrics in bulleted list")
    
        # 8. Verify blue callout
        callout_found = False
        for i in range(metrics_idx, min(metrics_idx + 20, len(all_blocks))):
            if all_blocks[i].get("type") == "callout":
                bg = all_blocks[i].get("properties", {}).get("backgroundColor", "")
                icon = all_blocks[i].get("properties", {}).get("icon", "")
                content = str(all_blocks[i].get("content", "") or all_blocks[i].get("text", ""))
                if "blue" in bg.lower() and "💡" in icon and "Sprint velocity" in content:
                    callout_found = True
                    break
    
        if not callout_found:
            errors.append("[X] Blue callout with Sprint velocity not found")
        else:
            checks_passed.append("[C] Blue callout with Sprint velocity found")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

    # -----------------------------------------------------------------------------
    # create-style-guide-callout-reference-v2
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_create_style_guide_callout_reference(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Task: Create Style Guide Reference child page analyzing parent's callouts.
    
    Validates:
    1. "🎨 Style Guide Reference" exists as child
    2. Heading structure with Color Guidelines
    3. heading_3 sections for each color with example callouts
    4. Usage Statistics section with counts sorted by frequency
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    # 1. Find Project Guidelines & Best Practices page
    try:
        parent_results = final_state_backend.query({
            "collection": "pages",
            "filter": {"title": "Project Guidelines & Best Practices"}
        })
    
        if not parent_results:
            errors.append("[X] Project Guidelines & Best Practices page not found")
        else:
            checks_passed.append("[C] Project Guidelines & Best Practices page found")
    
        parent_page = parent_results[0]
        parent_id = parent_page.get("_id")
    
        # 2. Verify Style Guide Reference exists as child
        child_results = final_state_backend.query({
            "collection": "pages",
            "filter": {"parentId": parent_id}
        })
    
        style_guide_page = None
        for page in child_results:
            if "Style Guide Reference" in page.get("title", ""):
                style_guide_page = page
                break
    
        if not style_guide_page:
            errors.append("[X] '🎨 Style Guide Reference' page not found as child")
        else:
            checks_passed.append("[C] '🎨 Style Guide Reference' page found as child")
    
        # 3. Analyze parent page callouts
        parent_blocks = final_state_backend.query({
            "collection": "blocks",
            "filter": {"pageId": parent_id}
        })
        color_counts = {}
        for block in parent_blocks:
            if block.get("type") == "callout":
                bg = block.get("properties", {}).get("backgroundColor", "").lower()
                if bg:
                    color_name = bg.replace("_background", "").replace("background", "").strip()
                    color_counts[color_name] = color_counts.get(color_name, 0) + 1
    
        # 4. Check Style Guide Reference content
        guide_blocks = final_state_backend.query({
            "collection": "blocks",
            "filter": {"pageId": style_guide_page.get("_id")}
        })
    
        # Check heading_1
        h1_found = False
        for block in guide_blocks:
            if block.get("type") in ["heading1", "heading_1"]:
                content = str(block.get("content", "") or block.get("text", ""))
                if "🎨" in content and "Style Guide Reference" in content:
                    h1_found = True
                    break
    
        if not h1_found:
            errors.append("[X] '🎨 Style Guide Reference' heading_1 not found")
        else:
            checks_passed.append("[C] '🎨 Style Guide Reference' heading_1 found")
    
        # Check heading_2 for Color Guidelines
        h2_found = False
        for block in guide_blocks:
            if block.get("type") in ["heading2", "heading_2"]:
                content = str(block.get("content", "") or block.get("text", ""))
                if "Callout Color Guidelines" in content:
                    h2_found = True
                    break
    
        if not h2_found:
            errors.append("[X] 'Callout Color Guidelines' heading_2 not found")
        else:
            checks_passed.append("[C] 'Callout Color Guidelines' heading_2 found")
    
        # 5. Check for heading_3 sections for each color
        expected_colors = ["yellow", "orange", "red", "green", "blue", "gray"]
        found_colors = []
        for block in guide_blocks:
            if block.get("type") in ["heading3", "heading_3"]:
                content = str(block.get("content", "") or block.get("text", "")).lower()
                for color in expected_colors:
                    if color in content:
                        found_colors.append(color)
    
        if len(found_colors) < 6:
            missing = set(expected_colors) - set(found_colors)
            errors.append(f"[X] Missing color sections: {', '.join(missing)}")
        else:
            checks_passed.append(f"[C] has color sections")
    
        # 6. Check Usage Statistics section
        stats_found = False
        for block in guide_blocks:
            if block.get("type") in ["heading2", "heading_2"]:
                content = str(block.get("content", "") or block.get("text", ""))
                if "📊" in content and "Usage Statistics" in content:
                    stats_found = True
                    break
    
        if not stats_found:
            errors.append("[X] '📊 Usage Statistics' heading_2 not found")
        else:
            checks_passed.append("[C] '📊 Usage Statistics' heading_2 found")
    
        # 7. Verify total callout types paragraph
        total_found = False
        for block in guide_blocks:
            if block.get("type") == "paragraph":
                content = str(block.get("content", "") or block.get("text", ""))
                if "Total callout types" in content and "6" in content:
                    total_found = True
                    break
    
        if not total_found:
            errors.append("[X] Paragraph with 'Total callout types: 6' not found")
        else:
            checks_passed.append("[C] Paragraph with 'Total callout types: 6' found")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

    # -----------------------------------------------------------------------------
    # reorganize-handbook-swap-values-benefits-add-culture-v2
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_reorganize_handbook_swap_values_benefits_add_culture(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Task: Swap Our Values and Benefits sections, insert Company Culture section.
    
    Validates:
    1. Benefits section now at original Our Values position (order 2)
    2. Our Values section now at original Benefits position (order 11)
    3. Company Culture section exists between them
    4. Green callout with 🎯 icon
    5. 3 bulleted items with exact text
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    # 1. Find Company Handbook page
    try:
        page_results = final_state_backend.query({
            "collection": "pages",
            "filter": {"title": "Company Handbook"}
        })
    
        if not page_results:
            errors.append("[X] Company Handbook page not found")
        else:
            checks_passed.append("[C] Company Handbook page found")
    
        page = page_results[0]
        # Query blocks collection for this page
        all_blocks = final_state_backend.query({
            "collection": "blocks",
            "filter": {"pageId": page.get("_id")}
        })
    
        # 2. Find section positions
        values_idx = None
        benefits_idx = None
        culture_idx = None
    
        for i, block in enumerate(all_blocks):
            if block.get("type") in ["heading2", "heading_2"]:
                content = str(block.get("content", "") or block.get("text", ""))
                if "Our Values" in content:
                    values_idx = i
                elif "Benefits" in content:
                    benefits_idx = i
                elif "🌟" in content and "Company Culture" in content:
                    culture_idx = i
    
        if values_idx is None:
            errors.append("[X] 'Our Values' section not found")
        else:
            checks_passed.append("[C] 'Our Values' section found")
        if benefits_idx is None:
            errors.append("[X] 'Benefits' section not found")
        else:
            checks_passed.append("[C] 'Benefits' section found")
    
        # 3. Verify sections are swapped (Benefits should come before Our Values now)
        if benefits_idx >= values_idx:
            errors.append("[X] Sections not swapped: Benefits should appear before Our Values")
        else:
            checks_passed.append("[C] Sections swapped: Benefits should appear before Our Values")
    
        # 4. Check Company Culture section exists
        if culture_idx is None:
            errors.append("[X] '🌟 Company Culture' section not found")
        else:
            checks_passed.append("[C] '🌟 Company Culture' section found")
    
        # Verify Company Culture is between Benefits and values (or before Work Policies)
        if not (benefits_idx < culture_idx):
            errors.append("[X] Company Culture section not positioned correctly")
        else:
            checks_passed.append("[C] Company Culture section positioned correctly")
    
        # 5. Verify green callout
        callout_found = False
        for i in range(culture_idx + 1, min(culture_idx + 10, len(all_blocks))):
            if all_blocks[i].get("type") == "callout":
                bg = all_blocks[i].get("properties", {}).get("backgroundColor", "")
                icon = all_blocks[i].get("properties", {}).get("icon", "")
                content = str(all_blocks[i].get("content", "") or all_blocks[i].get("text", ""))
                if "green" in bg.lower() and "🎯" in icon and "continuous learning" in content.lower():
                    callout_found = True
                    break
    
        if not callout_found:
            errors.append("[X] Green callout with 🎯 icon not found after Company Culture")
        else:
            checks_passed.append("[C] Green callout with 🎯 icon found after Company Culture")
    
        # 6. Check 3 bulleted items
        expected_bullets = [
            "Monthly team building events",
            "Peer recognition program",
            "Innovation time"
        ]
    
        found_bullets = 0
        for i in range(culture_idx, min(culture_idx + 15, len(all_blocks))):
            if all_blocks[i].get("type") in ["bulleted_list_item", "bulletedListItem", "bulletedList"]:
                content = str(all_blocks[i].get("content", "") or all_blocks[i].get("text", ""))
                if any(expected in content for expected in expected_bullets):
                    found_bullets += 1
    
        if found_bullets < 3:
            errors.append(f"[X] Found {found_bullets} of 3 expected bulleted items")
        else:
            checks_passed.append(f"[C] Found {found_bullets} of 3 expected bulleted items")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

    # -----------------------------------------------------------------------------
    # create-component-library-interactive-catalog-v2
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_create_component_library_interactive_catalog(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Task: Add Interactive Component Catalog at beginning of Component Library page.
    
    Validates:
    1. "🧩 Interactive Component Catalog" heading_1 at beginning
    2. Purple callout with no icon
    3. 3 sections (Buttons, Forms, Layout) with JSX code blocks
    4. Storybook bookmarks after each code block
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    # 1. Find Component Library page
    try:
        page_results = final_state_backend.query({
            "collection": "pages",
            "filter": {"title": "Component Library"}
        })
    
        if not page_results:
            errors.append("[X] Component Library page not found")
        else:
            checks_passed.append("[C] Component Library page found")
    
        page = page_results[0]
        # Query blocks collection for this page
        all_blocks = final_state_backend.query({
            "collection": "blocks",
            "filter": {"pageId": page.get("_id")}
        })
    
        # 2. Check heading_1 at beginning
        h1_found = False
        h1_idx = None
        for i, block in enumerate(all_blocks[:10]):  # Check first 10 blocks
            if block.get("type") in ["heading1", "heading_1"]:
                content = str(block.get("content", "") or block.get("text", ""))
                if "🧩" in content and "Interactive Component Catalog" in content:
                    h1_found = True
                    h1_idx = i
                    break
    
        if not h1_found:
            errors.append("[X] '🧩 Interactive Component Catalog' heading_1 not found at beginning")
        else:
            checks_passed.append("[C] '🧩 Interactive Component Catalog' heading_1 found at beginning")
    
        # 3. Verify purple callout
        purple_callout_found = False
        for i in range(h1_idx, min(h1_idx + 5, len(all_blocks))):
            if all_blocks[i].get("type") == "callout":
                bg = all_blocks[i].get("properties", {}).get("backgroundColor", "")
                content = str(all_blocks[i].get("content", "") or all_blocks[i].get("text", ""))
                if "purple" in bg.lower() and "React component" in content:
                    purple_callout_found = True
                    break
    
        if not purple_callout_found:
            errors.append("[X] Purple callout not found")
        else:
            checks_passed.append("[C] Purple callout found")
    
        # 4. Check for 3 sections with code blocks
        sections = {"Buttons": False, "Forms": False, "Layout": False}
        code_count = 0
        bookmark_count = 0
    
        for i, block in enumerate(all_blocks):
            if block.get("type") in ["heading3", "heading_3"]:
                content = str(block.get("content", "") or block.get("text", ""))
                if "🔘" in content and "Buttons" in content:
                    sections["Buttons"] = True
                elif "📝" in content and "Forms" in content:
                    sections["Forms"] = True
                elif "🗂" in content and "Layout" in content:
                    sections["Layout"] = True
        
            if block.get("type") == "code":
                lang = block.get("properties", {}).get("language", "")
                if "jsx" in lang.lower():
                    code_count += 1
        
            if block.get("type") == "bookmark":
                url = str(block.get("properties", {}).get("url", ""))
                if "storybook.js.org" in url:
                    bookmark_count += 1
    
        if not all(sections.values()):
            missing = [k for k, v in sections.items() if not v]
            errors.append(f"[X] Missing sections: {', '.join(missing)}")
        else:
            checks_passed.append(f"[C] has sections")
    
        if code_count < 3:
            errors.append(f"[X] Expected 3 JSX code blocks, found {code_count}")
        else:
            checks_passed.append(f"[C] Found 3 JSX code blocks as expected")
    
        if bookmark_count < 3:
            errors.append(f"[X] Expected 3 Storybook bookmarks, found {bookmark_count}")
        else:
            checks_passed.append(f"[C] Found 3 Storybook bookmarks as expected")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

    # -----------------------------------------------------------------------------
    # add-weekly-standup-date-header-todos-v2
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_add_weekly_standup_date_header_todos(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Task: Add date header paragraph with 5 unchecked todos and divider.
    
    NOTE: Do NOT check for bold formatting - only validate text content "2024-02-05".
    
    Validates:
    1. Paragraph containing "2024-02-05" between specific blocks
    2. 5 unchecked todos with exact emoji-prefixed text
    3. Divider block after last todo
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    # 1. Find Weekly Standup Template page
    try:
        page_results = final_state_backend.query({
            "collection": "pages",
            "filter": {"title": "Weekly Standup Template"}
        })
    
        if not page_results:
            errors.append("[X] Weekly Standup Template page not found")
        else:
            checks_passed.append("[C] Weekly Standup Template page found")
    
        page = page_results[0]
        # Query blocks collection for this page
        all_blocks = final_state_backend.query({
            "collection": "blocks",
            "filter": {"pageId": page.get("_id")}
        })
    
        # 2. Find paragraph containing "2024-02-05"
        date_para_idx = None
        for i, block in enumerate(all_blocks):
            if block.get("type") == "paragraph":
                content = str(block.get("content", "") or block.get("text", ""))
                if "2024-02-05" in content:
                    date_para_idx = i
                    break
    
        if date_para_idx is None:
            errors.append("[X] Paragraph containing '2024-02-05' not found")
        else:
            checks_passed.append("[C] Paragraph containing '2024-02-05' found")
    
        # 3. Verify 5 unchecked todos after date header
        expected_todos = [
            "🔍 Review security audit findings",
            "📊 Analyze Q1 performance metrics",
            "🎯 Define sprint velocity targets",
            "💻 Implement OAuth2 integration",
            "📝 Update API documentation with examples"
        ]
    
        found_todos = []
        for i in range(date_para_idx + 1, min(date_para_idx + 10, len(all_blocks))):
            if all_blocks[i].get("type") == "todo":
                content = str(all_blocks[i].get("content", "") or all_blocks[i].get("text", ""))
                checked = all_blocks[i].get("properties", {}).get("checked", False)
                if not checked:
                    found_todos.append(content)
    
        matching_count = 0
        for expected in expected_todos:
            if any(expected in found for found in found_todos):
                matching_count += 1
    
        if matching_count < 5:
            errors.append(f"[X] Found {matching_count} of 5 expected unchecked todos")
        else:
            checks_passed.append(f"[C] Found {matching_count} of 5 expected unchecked todos")
    
        # 4. Verify divider after todos
        divider_found = False
        for i in range(date_para_idx + 1, min(date_para_idx + 10, len(all_blocks))):
            if all_blocks[i].get("type") == "divider":
                divider_found = True
                break
    
        if not divider_found:
            errors.append("[X] Divider block not found after todos")
        else:
            checks_passed.append("[C] Divider block found after todos")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

    # -----------------------------------------------------------------------------
    # create-documentation-quality-report-v2
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_create_documentation_quality_report(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Task: Create Documentation Quality Report as child of Project Documentation.
    
    Validates:
    1. Report exists as child with proper structure
    2. Tree-like hierarchy representation
    3. Blue callout with accurate counts
    4. Individual page analysis with stats
    5. Recommendations section
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    # 1. Find Project Documentation page
    try:
        parent_results = final_state_backend.query({
            "collection": "pages",
            "filter": {"title": "Project Documentation"}
        })
    
        if not parent_results:
            errors.append("[X] Project Documentation page not found")
        else:
            checks_passed.append("[C] Project Documentation page found")
    
        parent_page = parent_results[0]
        parent_id = parent_page.get("_id")
    
        # 2. Verify Documentation Quality Report exists as child
        child_results = final_state_backend.query({
            "collection": "pages",
            "filter": {"parentId": parent_id}
        })
    
        report_page = None
        for page in child_results:
            if "Documentation Quality Report" in page.get("title", ""):
                report_page = page
                break
    
        if not report_page:
            errors.append("[X] '📑 Documentation Quality Report' not found as child")
        else:
            checks_passed.append("[C] '📑 Documentation Quality Report' found as child")
    
        report_blocks = final_state_backend.query({
            "collection": "blocks",
            "filter": {"pageId": report_page.get("_id")}
        })
    
        # 3. Check heading_1
        h1_found = False
        for block in report_blocks:
            if block.get("type") in ["heading1", "heading_1"]:
                content = str(block.get("content", "") or block.get("text", ""))
                if "📑" in content and "Documentation Quality Report" in content:
                    h1_found = True
                    break
    
        if not h1_found:
            errors.append("[X] '📑 Documentation Quality Report' heading_1 not found")
        else:
            checks_passed.append("[C] '📑 Documentation Quality Report' heading_1 found")
    
        # 4. Check for Documentation Structure heading
        structure_found = False
        for block in report_blocks:
            if block.get("type") in ["heading2", "heading_2"]:
                content = str(block.get("content", "") or block.get("text", ""))
                # Accept both construction (🏗) and factory (🏭) emoji due to encoding variations
                if ("🏗" in content or "🏭" in content) and "Documentation Structure" in content:
                    structure_found = True
                    break
    
        if not structure_found:
            errors.append("[X] '🏗️ Documentation Structure' heading_2 not found")
        else:
            checks_passed.append("[C] '🏗️ Documentation Structure' heading_2 found")
    
        # 5. Check for tree-like bulleted list
        tree_items = []
        for block in report_blocks:
            if block.get("type") in ["bulleted_list_item", "bulletedListItem", "bulletedList"]:
                content = str(block.get("content", "") or block.get("text", ""))
                if "Project Documentation" in content or "Architecture" in content or "─" in content:
                    tree_items.append(content)
    
        if len(tree_items) < 2:
            errors.append("[X] Tree-like hierarchy representation not found")
        else:
            checks_passed.append("[C] Tree-like hierarchy representation found")
    
        # 6. Check for Content Analysis heading and blue callout
        analysis_found = False
        blue_callout_found = False
    
        for block in report_blocks:
            if block.get("type") in ["heading2", "heading_2"]:
                content = str(block.get("content", "") or block.get("text", ""))
                if "📊" in content and "Content Analysis" in content:
                    analysis_found = True
        
            if block.get("type") == "callout":
                bg = block.get("properties", {}).get("backgroundColor", "")
                icon = block.get("properties", {}).get("icon", "")
                content = str(block.get("content", "") or block.get("text", ""))
                if "blue" in bg.lower() and "📈" in icon and "Total pages analyzed" in content:
                    blue_callout_found = True
    
        if not analysis_found:
            errors.append("[X] '📊 Content Analysis' heading_2 not found")
        else:
            checks_passed.append("[C] '📊 Content Analysis' heading_2 found")
    
        if not blue_callout_found:
            errors.append("[X] Blue callout with analysis statistics not found")
        else:
            checks_passed.append("[C] Blue callout with analysis statistics found")
    
        # 7. Check for Recommendations section
        recommendations_found = False
        for block in report_blocks:
            if block.get("type") in ["heading2", "heading_2"]:
                content = str(block.get("content", "") or block.get("text", ""))
                if "✅" in content and "Recommendations" in content:
                    recommendations_found = True
                    break
    
        if not recommendations_found:
            errors.append("[X] '✅ Recommendations' heading_2 not found")
        else:
            checks_passed.append("[C] '✅ Recommendations' heading_2 found")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

    # -----------------------------------------------------------------------------
    # reorganize-architecture-create-legacy-archive-v2
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_reorganize_architecture_create_legacy_archive(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Task: Create Legacy Systems Archive under Architecture, move Frontend Architecture into it.
    
    Validates:
    1. Legacy Systems Archive exists under Architecture
    2. Frontend Architecture moved under archive
    3. Frontend Architecture's children moved with it
    4. 3 new architecture pages created
    5. Each new page has heading_1 and update paragraph
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    # 1. Find Architecture page
    try:
        arch_results = final_state_backend.query({
            "collection": "pages",
            "filter": {"title": "Architecture"}
        })
    
        if not arch_results:
            errors.append("[X] Architecture page not found")
        else:
            checks_passed.append("[C] Architecture page found")
    
        arch_page = arch_results[0]
        arch_id = arch_page.get("_id")
    
        # 2. Verify Legacy Systems Archive exists as child
        archive_results = final_state_backend.query({
            "collection": "pages",
            "filter": {"title": "📦 Legacy Systems Archive"}
        })
    
        if not archive_results:
            # Try without emoji - use text search instead of fetching all pages
            archive_results = final_state_backend.query({
                "collection": "pages",
                "filter": {"$text": {"$search": "Legacy Systems Archive"}}
            })
            archive_page = None
            for p in archive_results:
                if "Legacy Systems Archive" in p.get("title", ""):
                    archive_page = p
                    break
            if not archive_page:
                errors.append("[X] 'Legacy Systems Archive' page not found")
            else:
                checks_passed.append("[C] 'Legacy Systems Archive' page found")
        else:
            archive_page = archive_results[0]
    
        if archive_page.get("parentId") != arch_id:
            errors.append("[X] Legacy Systems Archive is not under Architecture")
        else:
            checks_passed.append("[C] Legacy Systems Archive is under Architecture")
    
        archive_id = archive_page.get("_id")
    
        # 3. Check Frontend Architecture is under archive
        frontend_results = final_state_backend.query({
            "collection": "pages",
            "filter": {"title": "Frontend Architecture"}
        })
    
        if not frontend_results:
            errors.append("[X] Frontend Architecture page not found")
        else:
            checks_passed.append("[C] Frontend Architecture page found")
    
        frontend_page = frontend_results[0]
        if frontend_page.get("parentId") != archive_id:
            errors.append("[X] Frontend Architecture is not under Legacy Systems Archive")
        else:
            checks_passed.append("[C] Frontend Architecture is under Legacy Systems Archive")
    
        # 4. Verify Frontend Architecture's children moved with it
        frontend_children = final_state_backend.query({
            "collection": "pages",
            "filter": {"parentId": frontend_page.get("_id")}
        })
    
        if len(frontend_children) < 2:
            errors.append("[X] Frontend Architecture children not found (Component Library, State Management)")
        else:
            checks_passed.append("[C] Frontend Architecture children found (Component Library, State Management)")
    
        # 5. Check for 3 new architecture pages under Architecture
        expected_new_pages = [
            "Microservices Architecture",
            "Event-Driven Design",
            "API Gateway Pattern"
        ]
    
        arch_children = final_state_backend.query({
            "collection": "pages",
            "filter": {"parentId": arch_id}
        })
    
        found_new_pages = 0
        for page in arch_children:
            title = page.get("title", "")
            if any(expected in title for expected in expected_new_pages):
                found_new_pages += 1
    
        if found_new_pages < 3:
            errors.append(f"[X] Expected 3 new architecture pages, found {found_new_pages}")
        else:
            checks_passed.append(f"[C] Found 3 new architecture pages as expected")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

    # -----------------------------------------------------------------------------
    # add-code-examples-python-memoize-typescript-tip-v2
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_add_code_examples_python_memoize_typescript_tip(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Task: Insert Python memoize function, add green callout to Typescript section,
    add Code Statistics section.
    
    Validates:
    1. Python memoize code block at correct position
    2. Green callout with ✨ icon after Typescript heading
    3. Code Statistics heading_2 with accurate count
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    # 1. Find Code Examples Repository page
    try:
        page_results = final_state_backend.query({
            "collection": "pages",
            "filter": {"title": "Code Examples Repository"}
        })
    
        if not page_results:
            errors.append("[X] Code Examples Repository page not found")
        else:
            checks_passed.append("[C] Code Examples Repository page found")
    
        page = page_results[0]
        # Query blocks collection for this page
        all_blocks = final_state_backend.query({
            "collection": "blocks",
            "filter": {"pageId": page.get("_id")}
        })
    
        # 2. Check for Python memoize code block
        memoize_found = False
        for block in all_blocks:
            if block.get("type") == "code":
                lang = block.get("properties", {}).get("language", "")
                content = str(block.get("content", "") or block.get("text", ""))
                if "python" in lang.lower() and "def memoize" in content and "cache" in content:
                    memoize_found = True
                    break
    
        if not memoize_found:
            errors.append("[X] Python memoize function code block not found")
        else:
            checks_passed.append("[C] Python memoize function code block found")
    
        # 3. Find Typescript Examples section
        typescript_idx = None
        for i, block in enumerate(all_blocks):
            if block.get("type") in ["heading2", "heading_2", "heading3", "heading_3"]:
                content = str(block.get("content", "") or block.get("text", ""))
                if "Typescript" in content or "TypeScript" in content:
                    typescript_idx = i
                    break
    
        if typescript_idx is None:
            errors.append("[X] Typescript Examples section not found")
        else:
            checks_passed.append("[C] Typescript Examples section found")
    
        # 4. Check green callout after Typescript heading
        green_callout_found = False
        for i in range(typescript_idx + 1, min(typescript_idx + 5, len(all_blocks))):
            if all_blocks[i].get("type") == "callout":
                bg = all_blocks[i].get("properties", {}).get("backgroundColor", "")
                icon = all_blocks[i].get("properties", {}).get("icon", "")
                content = str(all_blocks[i].get("content", "") or all_blocks[i].get("text", ""))
                if "green" in bg.lower() and "✨" in icon and "strict mode" in content.lower():
                    green_callout_found = True
                    break
    
        if not green_callout_found:
            errors.append("[X] Green callout with ✨ icon not found after Typescript heading")
        else:
            checks_passed.append("[C] Green callout with ✨ icon found after Typescript heading")
    
        # 5. Count all code blocks on page
        code_count = sum(1 for block in all_blocks if block.get("type") == "code")
    
        # 6. Check for Code Statistics heading_2
        stats_found = False
        for block in all_blocks:
            if block.get("type") in ["heading2", "heading_2"]:
                content = str(block.get("content", "") or block.get("text", ""))
                if "📊" in content and "Code Statistics" in content:
                    stats_found = True
                    break
    
        if not stats_found:
            errors.append("[X] '📊 Code Statistics' heading_2 not found")
        else:
            checks_passed.append("[C] '📊 Code Statistics' heading_2 found")
    
        # 7. Verify paragraph with code count
        count_found = False
        for block in all_blocks:
            if block.get("type") == "paragraph":
                content = str(block.get("content", "") or block.get("text", ""))
                if "Total code examples" in content and str(code_count) in content:
                    count_found = True
                    break
    
        if not count_found:
            errors.append(f"[X] Paragraph with correct code count ({code_count}) not found")
        else:
            checks_passed.append(f"[C] Paragraph with correct code count ({code_count}) found")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

    # -----------------------------------------------------------------------------
    # create-team-dashboard-meeting-aggregation-v2
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_create_team_dashboard_meeting_aggregation(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Task: Create Team Dashboard at root, search and list all Meeting pages.
    
    Validates:
    1. Team Dashboard exists at root (no parentId)
    2. Heading structure
    3. Accurate count of Meeting pages
    4. heading_3 for each meeting page with metadata
    5. Green callout with statistics
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    # 1. Verify Team Dashboard exists at root
    # Use regex to find pages with "Team Dashboard" in title (avoids text index timing issues)
    try:
        dashboard_results = final_state_backend.query({
            "collection": "pages",
            "filter": {"title": {"$regex": "Team Dashboard"}}
        })
    
        dashboard_page = None
        for page in dashboard_results:
            title = page.get("title", "")
            if "Team Dashboard" in title:
                if not page.get("parentId"):  # Root level (no parent)
                    dashboard_page = page
                    break
    
        if not dashboard_page:
            errors.append("[X] Team Dashboard page not found at root level")
        else:
            checks_passed.append("[C] Team Dashboard page found at root level")
    
        dashboard_blocks = final_state_backend.query({
            "collection": "blocks",
            "filter": {"pageId": dashboard_page.get("_id")}
        })
    
        # 2. Check heading_1
        h1_found = False
        for block in dashboard_blocks:
            if block.get("type") in ["heading1", "heading_1"]:
                content = str(block.get("content", "") or block.get("text", ""))
                if "👥" in content and "Team Dashboard" in content:
                    h1_found = True
                    break
    
        if not h1_found:
            errors.append("[X] '👥 Team Dashboard' heading_1 not found")
        else:
            checks_passed.append("[C] '👥 Team Dashboard' heading_1 found")
    
        # 3. Search for all pages with "Meeting" in title
        # Use regex to find pages with "Meeting" (avoids text index timing issues)
        all_pages = final_state_backend.query({
            "collection": "pages",
            "filter": {"title": {"$regex": "Meeting"}}
        })
        meeting_pages = [p for p in all_pages if "Meeting" in p.get("title", "")]
        meeting_count = len(meeting_pages)
    
        # 4. Check heading_2 for Meeting Pages Overview
        overview_found = False
        for block in dashboard_blocks:
            if block.get("type") in ["heading2", "heading_2"]:
                content = str(block.get("content", "") or block.get("text", ""))
                if "📅" in content and "Meeting Pages Overview" in content:
                    overview_found = True
                    break
    
        if not overview_found:
            errors.append("[X] '📅 Meeting Pages Overview' heading_2 not found")
        else:
            checks_passed.append("[C] '📅 Meeting Pages Overview' heading_2 found")
    
        # 5. Verify paragraph with meeting count
        count_found = False
        for block in dashboard_blocks:
            if block.get("type") == "paragraph":
                content = str(block.get("content", "") or block.get("text", ""))
                if "Total meeting pages found" in content and str(meeting_count) in content:
                    count_found = True
                    break
    
        if not count_found:
            errors.append(f"[X] Paragraph with correct meeting count ({meeting_count}) not found")
        else:
            checks_passed.append(f"[C] Paragraph with correct meeting count ({meeting_count}) found")
    
        # 6. Check for heading_3 entries for meeting pages
        h3_count = sum(1 for block in dashboard_blocks 
                       if block.get("type") in ["heading3", "heading_3"] 
                       and "📝" in str(block.get("content", "") or block.get("text", "")))
    
        if h3_count < min(meeting_count, 2):  # At least some meeting pages listed
            errors.append("[X] Meeting pages not properly listed with heading_3")
        else:
            checks_passed.append("[C] Meeting pages properly listed with heading_3")
    
        # 7. Check for metadata paragraphs (Created by and Last updated)
        created_by_count = sum(1 for block in dashboard_blocks
                              if block.get("type") == "paragraph"
                              and "Created by:" in str(block.get("content", "") or block.get("text", "")))
    
        last_updated_count = sum(1 for block in dashboard_blocks
                                if block.get("type") == "paragraph"
                                and "Last updated:" in str(block.get("content", "") or block.get("text", "")))
    
        if created_by_count < min(meeting_count, 2):
            errors.append("[X] Missing 'Created by:' paragraphs for meeting pages")
        else:
            checks_passed.append("[C] has 'Created by:' paragraphs for meeting pages")
    
        if last_updated_count < min(meeting_count, 2):
            errors.append("[X] Missing 'Last updated:' paragraphs for meeting pages")
        else:
            checks_passed.append("[C] has 'Last updated:' paragraphs for meeting pages")
    
        # 8. Check for divider after meeting pages
        divider_found = any(block.get("type") == "divider" for block in dashboard_blocks)
        if not divider_found:
            errors.append("[X] Divider not found after meeting pages section")
        else:
            checks_passed.append("[C] Divider found after meeting pages section")
    
        # 9. Check for Workspace Statistics section and green callout
        stats_found = False
        green_callout_found = False
    
        for block in dashboard_blocks:
            if block.get("type") in ["heading2", "heading_2"]:
                content = str(block.get("content", "") or block.get("text", ""))
                if "📊" in content and "Workspace Statistics" in content:
                    stats_found = True
        
            if block.get("type") == "callout":
                bg = block.get("properties", {}).get("backgroundColor", "")
                icon = block.get("properties", {}).get("icon", "")
                content = str(block.get("content", "") or block.get("text", ""))
                if "green" in bg.lower() and "✅" in icon and "aggregates" in content.lower():
                    green_callout_found = True
    
        if not stats_found:
            errors.append("[X] '📊 Workspace Statistics' heading_2 not found")
        else:
            checks_passed.append("[C] '📊 Workspace Statistics' heading_2 found")
    
        if not green_callout_found:
            errors.append("[X] Green callout with ✅ icon not found")
        else:
            checks_passed.append("[C] Green callout with ✅ icon found")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

    # -----------------------------------------------------------------------------
    # add-sprint-planning-risk-assessment-v2
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_add_sprint_planning_risk_assessment(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Task: Insert Risk Assessment section with heading, paragraph, 4 bulleted risks,
    and orange callout.
    
    Validates:
    1. "🚨 Risk Assessment" heading_2 after Sprint Goals, before Action Items
    2. Paragraph about key risks
    3. 4 bulleted items with ⚠️ prefix
    4. Orange callout without icon
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    # 1. Find Sprint Planning - Jan 15 page
    try:
        page_results = final_state_backend.query({
            "collection": "pages",
            "filter": {"title": "Sprint Planning - Jan 15"}
        })
    
        if not page_results:
            errors.append("[X] Sprint Planning - Jan 15 page not found")
        else:
            checks_passed.append("[C] Sprint Planning - Jan 15 page found")
    
        page = page_results[0]
        # Query blocks collection for this page
        all_blocks = final_state_backend.query({
            "collection": "blocks",
            "filter": {"pageId": page.get("_id")}
        })
    
        # 2. Find Risk Assessment heading
        risk_idx = None
        for i, block in enumerate(all_blocks):
            if block.get("type") in ["heading2", "heading_2"]:
                content = str(block.get("content", "") or block.get("text", ""))
                if "🚨" in content and "Risk Assessment" in content:
                    risk_idx = i
                    break
    
        if risk_idx is None:
            errors.append("[X] '🚨 Risk Assessment' heading not found")
        else:
            checks_passed.append("[C] '🚨 Risk Assessment' heading found")
    
        # 3. Verify paragraph about key risks
        paragraph_found = False
        for i in range(risk_idx + 1, min(risk_idx + 5, len(all_blocks))):
            if all_blocks[i].get("type") == "paragraph":
                content = str(all_blocks[i].get("content", "") or all_blocks[i].get("text", ""))
                if "Key risks identified" in content:
                    paragraph_found = True
                    break
    
        if not paragraph_found:
            errors.append("[X] Paragraph about key risks not found")
        else:
            checks_passed.append("[C] Paragraph about key risks found")
    
        # 4. Check 4 bulleted items with ⚠️ prefix
        risk_items = []
        for i in range(risk_idx, min(risk_idx + 15, len(all_blocks))):
            if all_blocks[i].get("type") in ["bulleted_list_item", "bulletedListItem", "bulletedList"]:
                content = str(all_blocks[i].get("content", "") or all_blocks[i].get("text", ""))
                if "⚠" in content:
                    risk_items.append(content)
    
        if len(risk_items) < 4:
            errors.append(f"[X] Expected 4 risk items with ⚠️ prefix, found {len(risk_items)}")
        else:
            checks_passed.append(f"[C] Found 4 risk items with ⚠️ prefix as expected")
    
        # 5. Verify orange callout without icon
        orange_callout_found = False
        for i in range(risk_idx, min(risk_idx + 20, len(all_blocks))):
            if all_blocks[i].get("type") == "callout":
                bg = all_blocks[i].get("properties", {}).get("backgroundColor", "")
                content = str(all_blocks[i].get("content", "") or all_blocks[i].get("text", ""))
                if "orange" in bg.lower() and "Mitigation" in content and "standups" in content.lower():
                    orange_callout_found = True
                    break
    
        if not orange_callout_found:
            errors.append("[X] Orange callout with mitigation text not found")
        else:
            checks_passed.append("[C] Orange callout with mitigation text found")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

    # -----------------------------------------------------------------------------
    # create-documentation-health-check-v2
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_create_documentation_health_check(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Task: Create Documentation Health Check child page with Architecture analysis.
    
    Validates:
    1. Health Check page exists as child of Project Documentation
    2. Architecture sub-page count paragraph
    3. Hierarchy bulleted list with indentation
    4. 3 unchecked todos with exact text
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    # 1. Find Project Documentation page
    try:
        parent_results = final_state_backend.query({
            "collection": "pages",
            "filter": {"title": "Project Documentation"}
        })
    
        if not parent_results:
            errors.append("[X] Project Documentation page not found")
        else:
            checks_passed.append("[C] Project Documentation page found")
    
        parent_page = parent_results[0]
        parent_id = parent_page.get("_id")
    
        # 2. Verify Documentation Health Check exists as child
        child_results = final_state_backend.query({
            "collection": "pages",
            "filter": {"parentId": parent_id}
        })
    
        health_check_page = None
        for page in child_results:
            if "Documentation Health Check" in page.get("title", ""):
                health_check_page = page
                break
    
        if not health_check_page:
            errors.append("[X] '🏥 Documentation Health Check' not found as child")
        else:
            checks_passed.append("[C] '🏥 Documentation Health Check' found as child")
    
        health_blocks = final_state_backend.query({
            "collection": "blocks",
            "filter": {"pageId": health_check_page.get("_id")}
        })
    
        # 3. Check heading_1
        h1_found = False
        for block in health_blocks:
            if block.get("type") in ["heading1", "heading_1"]:
                content = str(block.get("content", "") or block.get("text", ""))
                if "🏥" in content and "Documentation Health Check" in content:
                    h1_found = True
                    break
    
        if not h1_found:
            errors.append("[X] '🏥 Documentation Health Check' heading_1 not found")
        else:
            checks_passed.append("[C] '🏥 Documentation Health Check' heading_1 found")
    
        # 3b. Check for '📊 Architecture Documentation Coverage' heading_2
        coverage_heading_found = False
        for block in health_blocks:
            if block.get("type") in ["heading2", "heading_2"]:
                content = str(block.get("content", "") or block.get("text", ""))
                if "📊" in content and "Architecture Documentation Coverage" in content:
                    coverage_heading_found = True
                    break
    
        if not coverage_heading_found:
            errors.append("[X] '📊 Architecture Documentation Coverage' heading_2 not found")
        else:
            checks_passed.append("[C] '📊 Architecture Documentation Coverage' heading_2 found")
    
        # 4. Find Architecture page and count children
        arch_results = final_state_backend.query({
            "collection": "pages",
            "filter": {"title": "Architecture"}
        })
    
        arch_subpage_count = 0
        if arch_results:
            arch_children = final_state_backend.query({
                "collection": "pages",
                "filter": {"parentId": arch_results[0].get("_id")}
            })
            arch_subpage_count = len(arch_children)
    
        # 5. Verify paragraph with sub-page count
        count_found = False
        for block in health_blocks:
            if block.get("type") == "paragraph":
                content = str(block.get("content", "") or block.get("text", ""))
                if "Total architecture sub-pages" in content:
                    count_found = True
                    break
    
        if not count_found:
            errors.append("[X] Paragraph with Architecture sub-page count not found")
        else:
            checks_passed.append("[C] Paragraph with Architecture sub-page count found")
    
        # 6. Check for Page Hierarchy Analysis heading
        hierarchy_found = False
        for block in health_blocks:
            if block.get("type") in ["heading2", "heading_2"]:
                content = str(block.get("content", "") or block.get("text", ""))
                if "🔍" in content and "Page Hierarchy Analysis" in content:
                    hierarchy_found = True
                    break
    
        if not hierarchy_found:
            errors.append("[X] '🔍 Page Hierarchy Analysis' heading_2 not found")
        else:
            checks_passed.append("[C] '🔍 Page Hierarchy Analysis' heading_2 found")
    
        # 7. Check for hierarchy bulleted list
        hierarchy_items = sum(1 for block in health_blocks
                             if block.get("type") in ["bulleted_list_item", "bulletedListItem", "bulletedList"]
                             and ("Architecture" in str(block.get("content", "") or block.get("text", ""))
                                  or "Frontend" in str(block.get("content", "") or block.get("text", ""))
                                  or "Component" in str(block.get("content", "") or block.get("text", ""))))
    
        if hierarchy_items < 2:
            errors.append("[X] Hierarchy bulleted list not found or incomplete")
        else:
            checks_passed.append("[C] Hierarchy bulleted list found or incomplete")
    
        # 8. Check Quick Actions heading and todos
        quick_actions_found = False
        for block in health_blocks:
            if block.get("type") in ["heading2", "heading_2"]:
                content = str(block.get("content", "") or block.get("text", ""))
                if "⚡" in content and "Quick Actions" in content:
                    quick_actions_found = True
                    break
    
        if not quick_actions_found:
            errors.append("[X] '⚡ Quick Actions' heading_2 not found")
        else:
            checks_passed.append("[C] '⚡ Quick Actions' heading_2 found")
    
        # 9. Check for 3 todos with specific text and emojis
        todo_texts = []
        for block in health_blocks:
            if block.get("type") == "todo":
                content = str(block.get("content", "") or block.get("text", ""))
                todo_texts.append(content)
    
        if len(todo_texts) < 3:
            errors.append(f"[X] Expected 3 todos, found {len(todo_texts)}")
        else:
            checks_passed.append(f"[C] Found 3 todos as expected")
    
        # Check for specific todos
        required_todos = [
            ("📝", "Review Component Library docs"),
            ("🔄", "Update State Management patterns"),
            (["🏗", "🏭"], "Add Backend Architecture section")  # Accept both construction and factory emoji due to encoding variations
        ]
    
        found_todos = 0
        for emoji_check, text in required_todos:
            # Handle both single emoji string and list of emojis
            emojis = emoji_check if isinstance(emoji_check, list) else [emoji_check]
            if any(any(emoji in todo for emoji in emojis) and text in todo for todo in todo_texts):
                found_todos += 1
    
        if found_todos < 3:
            errors.append(f"[X] Expected 3 specific todos with emojis, found {found_todos}")
        else:
            checks_passed.append(f"[C] Found 3 specific todos with emojis as expected")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

    # -----------------------------------------------------------------------------
    # add-engineering-wiki-api-documentation-standards-v2
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_add_engineering_wiki_api_documentation_standards(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Task: Add comprehensive API Documentation Standards section.
    
    Validates:
    1. "🔌 API Documentation Standards" heading_2
    2. Green callout with ✅ icon
    3. "Required Sections" heading_3 with 5-item numbered list
    4. "Example Template" heading_3 with markdown code block
    5. Divider at end
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    # 1. Find Engineering Wiki page
    try:
        page_results = final_state_backend.query({
            "collection": "pages",
            "filter": {"title": "Engineering Wiki"}
        })
    
        if not page_results:
            errors.append("[X] Engineering Wiki page not found")
        else:
            checks_passed.append("[C] Engineering Wiki page found")
    
        page = page_results[0]
        # Query blocks collection for this page
        all_blocks = final_state_backend.query({
            "collection": "blocks",
            "filter": {"pageId": page.get("_id")}
        })
    
        # 2. Check for heading_2 "🔌 API Documentation Standards"
        standards_idx = None
        for i, block in enumerate(all_blocks):
            if block.get("type") in ["heading2", "heading_2"]:
                content = str(block.get("content", "") or block.get("text", ""))
                if "🔌" in content and "API Documentation Standards" in content:
                    standards_idx = i
                    break
    
        if standards_idx is None:
            errors.append("[X] '🔌 API Documentation Standards' heading not found")
        else:
            checks_passed.append("[C] '🔌 API Documentation Standards' heading found")
    
        # 3. Verify green callout with ✅ icon
        green_callout_found = False
        for i in range(standards_idx + 1, min(standards_idx + 5, len(all_blocks))):
            if all_blocks[i].get("type") == "callout":
                bg = all_blocks[i].get("properties", {}).get("backgroundColor", "")
                icon = all_blocks[i].get("properties", {}).get("icon", "")
                content = str(all_blocks[i].get("content", "") or all_blocks[i].get("text", ""))
                if "green" in bg.lower() and "✅" in icon and "documented" in content.lower():
                    green_callout_found = True
                    break
    
        if not green_callout_found:
            errors.append("[X] Green callout with ✅ icon not found")
        else:
            checks_passed.append("[C] Green callout with ✅ icon found")
    
        # 4. Check for "Required Sections" heading_3
        required_sections_found = False
        for i in range(standards_idx, min(standards_idx + 15, len(all_blocks))):
            if all_blocks[i].get("type") in ["heading3", "heading_3"]:
                content = str(all_blocks[i].get("content", "") or all_blocks[i].get("text", ""))
                if "Required Sections" in content:
                    required_sections_found = True
                    break
    
        if not required_sections_found:
            errors.append("[X] 'Required Sections' heading_3 not found")
        else:
            checks_passed.append("[C] 'Required Sections' heading_3 found")
    
        # 5. Check numbered list with 5 items
        numbered_items = []
        for i in range(standards_idx, min(standards_idx + 25, len(all_blocks))):
            if all_blocks[i].get("type") in ["numbered_list_item", "numberedListItem", "numberedList"]:
                content = str(all_blocks[i].get("content", "") or all_blocks[i].get("text", ""))
                numbered_items.append(content)
    
        if len(numbered_items) < 5:
            errors.append(f"[X] Expected 5 numbered list items, found {len(numbered_items)}")
        else:
            checks_passed.append(f"[C] Found 5 numbered list items as expected")
    
        # 6. Check for "Example Template" heading_3
        template_found = False
        for i in range(standards_idx, min(standards_idx + 30, len(all_blocks))):
            if all_blocks[i].get("type") in ["heading3", "heading_3"]:
                content = str(all_blocks[i].get("content", "") or all_blocks[i].get("text", ""))
                if "Example Template" in content:
                    template_found = True
                    break
    
        if not template_found:
            errors.append("[X] 'Example Template' heading_3 not found")
        else:
            checks_passed.append("[C] 'Example Template' heading_3 found")
    
        # 7. Check markdown code block
        markdown_code_found = False
        for i in range(standards_idx, min(standards_idx + 35, len(all_blocks))):
            if all_blocks[i].get("type") == "code":
                lang = all_blocks[i].get("properties", {}).get("language", "")
                content = str(all_blocks[i].get("content", "") or all_blocks[i].get("text", ""))
                if "markdown" in lang.lower() and "GET /api" in content:
                    markdown_code_found = True
                    break
    
        if not markdown_code_found:
            errors.append("[X] Markdown code block with API example not found")
        else:
            checks_passed.append("[C] Markdown code block with API example found")
    
        # 8. Check for divider
        divider_found = False
        for i in range(standards_idx, min(standards_idx + 40, len(all_blocks))):
            if all_blocks[i].get("type") == "divider":
                divider_found = True
                break
    
        if not divider_found:
            errors.append("[X] Divider block not found at section end")
        else:
            checks_passed.append("[C] Divider block found at section end")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

    # -----------------------------------------------------------------------------
    # create-project-documentation-navigation-system-v2
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_create_project_documentation_navigation_system(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Task: Add Quick Navigation system with navigation list and Documentation Health.
    
    Validates:
    1. "🧭 Quick Navigation" heading_2 after title, before existing content
    2. Yellow callout with ⚡ icon
    3. Navigation bulleted list
    4. "📊 Documentation Health" heading_2 with 3 paragraphs
    5. Overview sections for each child page
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    # 1. Find Project Documentation page
    try:
        page_results = final_state_backend.query({
            "collection": "pages",
            "filter": {"title": "Project Documentation"}
        })
    
        if not page_results:
            errors.append("[X] Project Documentation page not found")
        else:
            checks_passed.append("[C] Project Documentation page found")
    
        page = page_results[0]
        # Query blocks collection for this page
        all_blocks = final_state_backend.query({
            "collection": "blocks",
            "filter": {"pageId": page.get("_id")}
        })
    
        # 2. Check for "🧭 Quick Navigation" heading_2
        nav_found = False
        for block in all_blocks[:15]:  # Should be near beginning
            if block.get("type") in ["heading2", "heading_2"]:
                content = str(block.get("content", "") or block.get("text", ""))
                if "🧭" in content and "Quick Navigation" in content:
                    nav_found = True
                    break
    
        if not nav_found:
            errors.append("[X] '🧭 Quick Navigation' heading not found near beginning")
        else:
            checks_passed.append("[C] '🧭 Quick Navigation' heading found near beginning")
    
        # 3. Verify yellow callout with ⚡ icon
        yellow_callout_found = False
        for block in all_blocks:
            if block.get("type") == "callout":
                bg = block.get("properties", {}).get("backgroundColor", "")
                icon = block.get("properties", {}).get("icon", "")
                content = str(block.get("content", "") or block.get("text", ""))
                if "yellow" in bg.lower() and "⚡" in icon and "Jump to any section" in content:
                    yellow_callout_found = True
                    break
    
        if not yellow_callout_found:
            errors.append("[X] Yellow callout with ⚡ icon not found")
        else:
            checks_passed.append("[C] Yellow callout with ⚡ icon found")
    
        # 4. Check for navigation bulleted list
        nav_bullets = sum(1 for block in all_blocks
                         if block.get("type") in ["bulleted_list_item", "bulletedListItem", "bulletedList"]
                         and "-" in str(block.get("content", "") or block.get("text", "")))
    
        if nav_bullets < 2:
            errors.append("[X] Navigation bulleted list not found or insufficient items")
        else:
            checks_passed.append("[C] Navigation bulleted list found or insufficient items")
    
        # 4b. Check for divider after navigation list
        divider_found = any(block.get("type") == "divider" for block in all_blocks)
        if not divider_found:
            errors.append("[X] Divider not found after navigation list")
        else:
            checks_passed.append("[C] Divider found after navigation list")
    
        # 5. Check for "📊 Documentation Health" heading_2
        health_found = False
        for block in all_blocks:
            if block.get("type") in ["heading2", "heading_2"]:
                content = str(block.get("content", "") or block.get("text", ""))
                if "📊" in content and "Documentation Health" in content:
                    health_found = True
                    break
    
        if not health_found:
            errors.append("[X] '📊 Documentation Health' heading not found")
        else:
            checks_passed.append("[C] '📊 Documentation Health' heading found")
    
        # 6. Verify all 3 required statistics paragraphs
        total_pages_found = False
        recently_updated_found = False
        archived_found = False
    
        for block in all_blocks:
            if block.get("type") == "paragraph":
                content = str(block.get("content", "") or block.get("text", ""))
                if "Total documentation pages" in content:
                    total_pages_found = True
                elif "Recently updated" in content:
                    recently_updated_found = True
                elif "Archived pages" in content:
                    archived_found = True
    
        if not total_pages_found:
            errors.append("[X] Paragraph 'Total documentation pages: [count]' not found")
        else:
            checks_passed.append("[C] Paragraph 'Total documentation pages: [count]' found")
        if not recently_updated_found:
            errors.append("[X] Paragraph 'Recently updated (last 30 days): [count]' not found")
        else:
            checks_passed.append("[C] Paragraph 'Recently updated (last 30 days): [count]' found")
        if not archived_found:
            errors.append("[X] Paragraph 'Archived pages: [count]' not found")
        else:
            checks_passed.append("[C] Paragraph 'Archived pages: [count]' found")
    
        # 7. Check for child page overview sections (heading_3 and quote/bookmark blocks)
        overview_count = sum(1 for block in all_blocks
                            if block.get("type") in ["heading3", "heading_3"]
                            and "Overview" in str(block.get("content", "") or block.get("text", "")))
    
        if overview_count < 1:
            errors.append("[X] Child page overview sections not found")
        else:
            checks_passed.append("[C] Child page overview sections found")
    
        # 7b. Check for quote blocks (for page descriptions)
        quote_count = sum(1 for block in all_blocks if block.get("type") == "quote")
        if quote_count < 1:
            errors.append("[X] Quote blocks for page descriptions not found")
        else:
            checks_passed.append("[C] Quote blocks for page descriptions found")
    
        # 7c. Check for bookmark blocks (linking to child pages)
        bookmark_count = sum(1 for block in all_blocks if block.get("type") == "bookmark")
        if bookmark_count < 1:
            errors.append("[X] Bookmark blocks linking to child pages not found")
        else:
            checks_passed.append("[C] Bookmark blocks linking to child pages found")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

    # -----------------------------------------------------------------------------
    # add-project-guidelines-coverage-metrics-v2
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_add_project_guidelines_coverage_metrics(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Task: Insert green callout after yellow callout, add dividers after red callouts,
    add Coverage Report.
    
    Validates:
    1. Yellow callout about unit tests exists
    2. Green callout with 📊 icon appears right after
    3. Dividers after all red callouts
    4. "📈 Coverage Report Summary" heading_2
    5. Paragraph with accurate total callout count
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    # 1. Find Project Guidelines & Best Practices page
    try:
        page_results = final_state_backend.query({
            "collection": "pages",
            "filter": {"title": "Project Guidelines & Best Practices"}
        })
    
        if not page_results:
            errors.append("[X] Project Guidelines & Best Practices page not found")
        else:
            checks_passed.append("[C] Project Guidelines & Best Practices page found")
    
        page = page_results[0]
        # Query blocks collection for this page
        all_blocks = final_state_backend.query({
            "collection": "blocks",
            "filter": {"pageId": page.get("_id")}
        })
    
        # 2. Find yellow callout about unit tests
        yellow_callout_idx = None
        for i, block in enumerate(all_blocks):
            if block.get("type") == "callout":
                bg = block.get("properties", {}).get("backgroundColor", "")
                icon = block.get("properties", {}).get("icon", "")
                content = str(block.get("content", "") or block.get("text", ""))
                if "yellow" in bg.lower() and "💡" in icon and "unit tests" in content.lower():
                    yellow_callout_idx = i
                    break
    
        if yellow_callout_idx is None:
            errors.append("[X] Yellow callout about unit tests not found")
        else:
            checks_passed.append("[C] Yellow callout about unit tests found")
    
        # 3. Verify green callout appears right after
        green_callout_found = False
        for i in range(yellow_callout_idx + 1, min(yellow_callout_idx + 5, len(all_blocks))):
            if all_blocks[i].get("type") == "callout":
                bg = all_blocks[i].get("properties", {}).get("backgroundColor", "")
                icon = all_blocks[i].get("properties", {}).get("icon", "")
                content = str(all_blocks[i].get("content", "") or all_blocks[i].get("text", ""))
                if "green" in bg.lower() and "📊" in icon and "Code coverage" in content:
                    green_callout_found = True
                    break
    
        if not green_callout_found:
            errors.append("[X] Green callout with 📊 icon not found after yellow callout")
        else:
            checks_passed.append("[C] Green callout with 📊 icon found after yellow callout")
    
        # 4. Find all red callouts and check for dividers after each
        red_callout_indices = []
        for i, block in enumerate(all_blocks):
            if block.get("type") == "callout":
                bg = block.get("properties", {}).get("backgroundColor", "")
                if "red" in bg.lower():
                    red_callout_indices.append(i)
    
        dividers_after_red = 0
        for idx in red_callout_indices:
            if idx + 1 < len(all_blocks) and all_blocks[idx + 1].get("type") == "divider":
                dividers_after_red += 1
    
        if red_callout_indices and dividers_after_red < len(red_callout_indices):
            errors.append(f"[X] Expected dividers after {len(red_callout_indices)} red callouts, found {dividers_after_red}")
        else:
            checks_passed.append(f"[C] Expected dividers after {len(red_callout_indices)} red callouts, found {dividers_after_red}")
    
        # 5. Check for "📈 Coverage Report Summary" heading_2
        report_found = False
        for block in all_blocks:
            if block.get("type") in ["heading2", "heading_2"]:
                content = str(block.get("content", "") or block.get("text", ""))
                if "📈" in content and "Coverage Report Summary" in content:
                    report_found = True
                    break
    
        if not report_found:
            errors.append("[X] '📈 Coverage Report Summary' heading not found")
        else:
            checks_passed.append("[C] '📈 Coverage Report Summary' heading found")
    
        # 6. Count all callouts and verify paragraph
        total_callouts = sum(1 for block in all_blocks if block.get("type") == "callout")
    
        count_found = False
        for block in all_blocks:
            if block.get("type") == "paragraph":
                content = str(block.get("content", "") or block.get("text", ""))
                if "Total callout blocks" in content and str(total_callouts) in content:
                    count_found = True
                    break
    
        if not count_found:
            errors.append(f"[X] Paragraph with correct callout count ({total_callouts}) not found")
        else:
            checks_passed.append(f"[C] Paragraph with correct callout count ({total_callouts}) found")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

    # -----------------------------------------------------------------------------
    # create-advanced-search-analytics-v2
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_create_advanced_search_analytics(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Task: Create Advanced Search Analytics page at root, analyzing API and Documentation pages.
    
    Validates:
    1. Page exists at root with correct title
    2. "🔌 API-Related Pages" section with numbered list
    3. "📚 Documentation Pages Analysis" with purple callouts
    4. "🏷️ Icon Usage Statistics" with top 5 icons
    5. Summary paragraph with correct totals
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    # 1. Verify Advanced Search Analytics exists at root
    # Find the Analytics page first using regex (avoids text index timing issues)
    try:
        analytics_results = final_state_backend.query({
            "collection": "pages",
            "filter": {"title": {"$regex": "Advanced Search Analytics"}}
        })
    
        analytics_page = None
        for page in analytics_results:
            title = page.get("title", "")
            if "Advanced Search Analytics" in title:
                if not page.get("parentId"):  # Root level
                    analytics_page = page
                    break
    
        if not analytics_page:
            errors.append("[X] Advanced Search Analytics page not found at root level")
        else:
            checks_passed.append("[C] Advanced Search Analytics page found at root level")
    
        # Now find API and Documentation pages using regex
        all_pages = final_state_backend.query({
            "collection": "pages",
            "filter": {"$or": [
                {"title": {"$regex": "API"}},
                {"title": {"$regex": "Documentation"}}
            ]}
        })
    
        analytics_blocks = final_state_backend.query({
            "collection": "blocks",
            "filter": {"pageId": analytics_page.get("_id")}
        })
    
        # 2. Check heading_1
        h1_found = False
        for block in analytics_blocks:
            if block.get("type") in ["heading1", "heading_1"]:
                content = str(block.get("content", "") or block.get("text", ""))
                if "📊" in content and "Search-Driven Insights" in content:
                    h1_found = True
                    break
    
        if not h1_found:
            errors.append("[X] '📊 Search-Driven Insights' heading_1 not found")
        else:
            checks_passed.append("[C] '📊 Search-Driven Insights' heading_1 found")
    
        # 3. Search for pages with "API" in title
        api_pages = _find_pages_by_title(final_state_backend, "API")
        api_count = len(api_pages)
    
        # 4. Check for "🔌 API-Related Pages" heading_2
        api_heading_found = False
        for block in analytics_blocks:
            if block.get("type") in ["heading2", "heading_2"]:
                content = str(block.get("content", "") or block.get("text", ""))
                if "🔌" in content and "API-Related Pages" in content:
                    api_heading_found = True
                    break
    
        if not api_heading_found:
            errors.append("[X] '🔌 API-Related Pages' heading not found")
        else:
            checks_passed.append("[C] '🔌 API-Related Pages' heading found")
    
        # 4b. Check for numbered list items for API pages
        numbered_items = sum(1 for block in analytics_blocks
                            if block.get("type") in ["numbered_list_item", "numberedListItem", "numberedList", "numbered_list"]
                            and "Workspace:" in str(block.get("content", "") or block.get("text", "")))
    
        if numbered_items < min(api_count, 2):
            errors.append("[X] Numbered list items for API pages with workspace info not found")
        else:
            checks_passed.append("[C] Numbered list items for API pages with workspace info found")
    
        # 5. Search for pages with "Documentation" in title
        doc_pages = _find_pages_by_title(final_state_backend, "Documentation")
        doc_count = len(doc_pages)
    
        # 6. Check for "📚 Documentation Pages Analysis" heading_2
        doc_heading_found = False
        for block in analytics_blocks:
            if block.get("type") in ["heading2", "heading_2"]:
                content = str(block.get("content", "") or block.get("text", ""))
                if "📚" in content and "Documentation Pages Analysis" in content:
                    doc_heading_found = True
                    break
    
        if not doc_heading_found:
            errors.append("[X] '📚 Documentation Pages Analysis' heading not found")
        else:
            checks_passed.append("[C] '📚 Documentation Pages Analysis' heading found")
    
        # 7. Check for purple callouts
        purple_callout_count = sum(1 for block in analytics_blocks
                                   if block.get("type") == "callout"
                                   and "purple" in block.get("properties", {}).get("backgroundColor", "").lower())
    
        if purple_callout_count < min(doc_count, 2):
            errors.append("[X] Purple callouts for Documentation pages not found")
        else:
            checks_passed.append("[C] Purple callouts for Documentation pages found")
    
        # 8. Check for "🏷️ Icon Usage Statistics" heading_2
        icon_stats_found = False
        for block in analytics_blocks:
            if block.get("type") in ["heading2", "heading_2"]:
                content = str(block.get("content", "") or block.get("text", ""))
                if "🏷" in content and "Icon Usage Statistics" in content:
                    icon_stats_found = True
                    break
    
        if not icon_stats_found:
            errors.append("[X] '🏷️ Icon Usage Statistics' heading not found")
        else:
            checks_passed.append("[C] '🏷️ Icon Usage Statistics' heading found")
    
        # 8b. Check for bulleted list items for icon statistics
        icon_bullet_items = sum(1 for block in analytics_blocks
                               if block.get("type") in ["bulleted_list_item", "bulletedListItem", "bulletedList"]
                               and "Used in" in str(block.get("content", "") or block.get("text", ""))
                               and "pages" in str(block.get("content", "") or block.get("text", "")))
    
        if icon_bullet_items < 5:
            errors.append(f"[X] Expected at least 5 icon statistics bullet items, found {icon_bullet_items}")
        else:
            checks_passed.append(f"[C] Found at least 5 icon statistics bullet items ({icon_bullet_items})")
    
        # 9. Check summary paragraph
        summary_found = False
        for block in analytics_blocks:
            if block.get("type") == "paragraph":
                content = str(block.get("content", "") or block.get("text", ""))
                if "Analysis complete" in content and "API pages" in content and "documentation pages" in content:
                    summary_found = True
                    break
    
        if not summary_found:
            errors.append("[X] Summary paragraph not found")
        else:
            checks_passed.append("[C] Summary paragraph found")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

    # -----------------------------------------------------------------------------
    # create-workspace-analytics-coverage-report-v2
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_create_workspace_analytics_coverage_report(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Task: Create Workspace Analytics page at root analyzing Project Documentation.
    
    Validates:
    1. Page exists at root with correct title
    2. "📈 Documentation Coverage Report" heading_2
    3. Gray callout with accurate count
    4. Page Hierarchy section with tree-like list
    5. Recommendations numbered list
    6. Write the Docs bookmark
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    # 1. Verify Workspace Analytics exists at root
    # Use regex to find relevant pages (avoids text index timing issues)
    try:
        analytics_results = final_state_backend.query({
            "collection": "pages",
            "filter": {"title": {"$regex": "Workspace Analytics"}}
        })
    
        analytics_page = None
        for page in analytics_results:
            title = page.get("title", "")
            if "Workspace Analytics" in title:
                if not page.get("parentId"):  # Root level
                    analytics_page = page
                    break
    
        if not analytics_page:
            errors.append("[X] Workspace Analytics page not found at root level")
        else:
            checks_passed.append("[C] Workspace Analytics page found at root level")
    
        analytics_blocks = final_state_backend.query({
            "collection": "blocks",
            "filter": {"pageId": analytics_page.get("_id")}
        })
    
        # 2. Check heading_1
        h1_found = False
        for block in analytics_blocks:
            if block.get("type") in ["heading1", "heading_1"]:
                content = str(block.get("content", "") or block.get("text", ""))
                if "📊" in content and "Workspace Analytics" in content:
                    h1_found = True
                    break
    
        if not h1_found:
            errors.append("[X] '📊 Workspace Analytics' heading_1 not found")
        else:
            checks_passed.append("[C] '📊 Workspace Analytics' heading_1 found")
    
        # 3. Check for "📈 Documentation Coverage Report" heading_2
        coverage_found = False
        for block in analytics_blocks:
            if block.get("type") in ["heading2", "heading_2"]:
                content = str(block.get("content", "") or block.get("text", ""))
                if "📈" in content and "Documentation Coverage Report" in content:
                    coverage_found = True
                    break
    
        if not coverage_found:
            errors.append("[X] '📈 Documentation Coverage Report' heading not found")
        else:
            checks_passed.append("[C] '📈 Documentation Coverage Report' heading found")
    
        # 3b. Check for "Generated on [today's date]" paragraph
        generated_paragraph_found = False
        for block in analytics_blocks:
            if block.get("type") == "paragraph":
                content = str(block.get("content", "") or block.get("text", ""))
                if "Generated on" in content:
                    generated_paragraph_found = True
                    break
    
        if not generated_paragraph_found:
            errors.append("[X] 'Generated on [date]' paragraph not found")
        else:
            checks_passed.append("[C] 'Generated on [date]' paragraph found")
    
        # 4. Verify gray callout
        gray_callout_found = False
        for block in analytics_blocks:
            if block.get("type") == "callout":
                bg = block.get("properties", {}).get("backgroundColor", "")
                icon = block.get("properties", {}).get("icon", "")
                content = str(block.get("content", "") or block.get("text", ""))
                if "gray" in bg.lower() and "📁" in icon and "Total documentation pages analyzed" in content:
                    gray_callout_found = True
                    break
    
        if not gray_callout_found:
            errors.append("[X] Gray callout with 📁 icon not found")
        else:
            checks_passed.append("[C] Gray callout with 📁 icon found")
    
        # 5. Check for "🔍 Page Hierarchy" heading_2
        hierarchy_found = False
        for block in analytics_blocks:
            if block.get("type") in ["heading2", "heading_2"]:
                content = str(block.get("content", "") or block.get("text", ""))
                if "🔍" in content and "Page Hierarchy" in content:
                    hierarchy_found = True
                    break
    
        if not hierarchy_found:
            errors.append("[X] '🔍 Page Hierarchy' heading not found")
        else:
            checks_passed.append("[C] '🔍 Page Hierarchy' heading found")
    
        # 5b. Check for heading_3 '📚 Project Documentation'
        h3_proj_doc_found = False
        for block in analytics_blocks:
            if block.get("type") in ["heading3", "heading_3"]:
                content = str(block.get("content", "") or block.get("text", ""))
                if "📚" in content and "Project Documentation" in content:
                    h3_proj_doc_found = True
                    break
    
        if not h3_proj_doc_found:
            errors.append("[X] heading_3 '📚 Project Documentation' not found")
        else:
            checks_passed.append("[C] heading_3 '📚 Project Documentation' found")
    
        # 6. Check for tree-like bulleted list
        tree_items = sum(1 for block in analytics_blocks
                        if block.get("type") in ["bulleted_list_item", "bulletedListItem", "bulletedList"]
                        and ("└" in str(block.get("content", "") or block.get("text", ""))
                             or "Project Documentation" in str(block.get("content", "") or block.get("text", ""))))
    
        if tree_items < 1:
            errors.append("[X] Tree-like hierarchy list not found")
        else:
            checks_passed.append("[C] Tree-like hierarchy list found")
    
        # 7. Check for "⚡ Recommendations" heading_2
        recommendations_found = False
        for block in analytics_blocks:
            if block.get("type") in ["heading2", "heading_2"]:
                content = str(block.get("content", "") or block.get("text", ""))
                if "⚡" in content and "Recommendations" in content:
                    recommendations_found = True
                    break
    
        if not recommendations_found:
            errors.append("[X] '⚡ Recommendations' heading not found")
        else:
            checks_passed.append("[C] '⚡ Recommendations' heading found")
    
        # 8. Check for numbered list with 3 items
        numbered_items = sum(1 for block in analytics_blocks
                            if block.get("type") in ["numbered_list_item", "numberedListItem", "numberedList"])
    
        if numbered_items < 3:
            errors.append(f"[X] Expected 3 numbered recommendations, found {numbered_items}")
        else:
            checks_passed.append(f"[C] Found 3 numbered recommendations as expected")
    
        # 9. Verify bookmark
        bookmark_found = False
        for block in analytics_blocks:
            if block.get("type") == "bookmark":
                url = str(block.get("properties", {}).get("url", ""))
                caption = str(block.get("properties", {}).get("caption", ""))
                if "writethedocs.org" in url and "Documentation Best Practices" in caption:
                    bookmark_found = True
                    break
    
        if not bookmark_found:
            errors.append("[X] Write the Docs bookmark not found")
        else:
            checks_passed.append("[C] Write the Docs bookmark found")
    
        # 10. Check for divider at the end (before or after bookmark)
        divider_found = any(block.get("type") == "divider" for block in analytics_blocks)
    
        if not divider_found:
            errors.append("[X] Divider block not found")
        else:
            checks_passed.append("[C] Divider block found")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

    # -----------------------------------------------------------------------------
    # add-bug-tracker-date-header-updates-v2
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_add_bug_tracker_date_header_updates(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Task: Add date header in Medium Priority section, add 3 todos, update existing todo.
    
    NOTE: Do NOT check for bold formatting - only validate text content "2024-02-15 Updates".
    
    Validates:
    1. Paragraph containing "2024-02-15 Updates" between specific blocks
    2. 3 unchecked todos with emoji prefixes
    3. Existing todo updated with " (RESOLVED)" suffix
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    # 1. Find Bug Tracker page
    try:
        page_results = final_state_backend.query({
            "collection": "pages",
            "filter": {"title": "Bug Tracker"}
        })
    
        if not page_results:
            errors.append("[X] Bug Tracker page not found")
        else:
            checks_passed.append("[C] Bug Tracker page found")
    
        page = page_results[0]
        # Query blocks collection for this page
        all_blocks = final_state_backend.query({
            "collection": "blocks",
            "filter": {"pageId": page.get("_id")}
        })
    
        # 2. Find Medium Priority heading
        medium_priority_idx = None
        for i, block in enumerate(all_blocks):
            if block.get("type") in ["heading2", "heading_2", "heading3", "heading_3"]:
                content = str(block.get("content", "") or block.get("text", ""))
                if "Medium Priority" in content:
                    medium_priority_idx = i
                    break
    
        if medium_priority_idx is None:
            errors.append("[X] 'Medium Priority' section not found")
        else:
            checks_passed.append("[C] 'Medium Priority' section found")
    
        # 3. Find the specific todo "Search results not updating in real-time"
        search_todo_idx = None
        for i in range(medium_priority_idx, len(all_blocks)):
            if all_blocks[i].get("type") == "todo":
                content = str(all_blocks[i].get("content", "") or all_blocks[i].get("text", ""))
                if "Search results not updating in real-time" in content:
                    search_todo_idx = i
                    break
    
        if search_todo_idx is None:
            errors.append("[X] Todo 'Search results not updating in real-time' not found")
        else:
            checks_passed.append("[C] Todo 'Search results updating in real-time' found")
    
        # 4. Find Low Priority heading
        low_priority_idx = None
        for i in range(medium_priority_idx, len(all_blocks)):
            if all_blocks[i].get("type") in ["heading2", "heading_2", "heading3", "heading_3"]:
                content = str(all_blocks[i].get("content", "") or all_blocks[i].get("text", ""))
                if "Low Priority" in content:
                    low_priority_idx = i
                    break
    
        if low_priority_idx is None:
            errors.append("[X] 'Low Priority' section not found")
        else:
            checks_passed.append("[C] 'Low Priority' section found")
    
        # 5. Find paragraph containing "2024-02-15 Updates" between search_todo and low_priority
        date_para_idx = None
        for i in range(search_todo_idx + 1, low_priority_idx):
            if all_blocks[i].get("type") == "paragraph":
                content = str(all_blocks[i].get("content", "") or all_blocks[i].get("text", ""))
                if "2024-02-15 Updates" in content:
                    date_para_idx = i
                    break
    
        if date_para_idx is None:
            errors.append("[X] Paragraph containing '2024-02-15 Updates' not found in correct position (after search todo, before Low Priority)")
        else:
            checks_passed.append("[C] Paragraph containing '2024-02-15 Updates' found in correct position (after search todo, before Low Priority)")
    
        # 3. Check for 3 new unchecked todos with emoji prefixes
        expected_todos = [
            "🔍 Fix search indexing for archived pages",
            "⚡ Optimize database query performance",
            "🛡️ Add rate limiting to API endpoints"
        ]
    
        found_new_todos = 0
        for block in all_blocks:
            if block.get("type") == "todo":
                content = str(block.get("content", "") or block.get("text", ""))
                checked = block.get("properties", {}).get("checked", False)
                if not checked and any(expected in content for expected in expected_todos):
                    found_new_todos += 1
    
        if found_new_todos < 3:
            errors.append(f"[X] Expected 3 new unchecked todos, found {found_new_todos}")
        else:
            checks_passed.append(f"[C] Found 3 new unchecked todos as expected")
    
        # 4. Verify existing todo updated with " (RESOLVED)"
        resolved_found = False
        for block in all_blocks:
            if block.get("type") == "todo":
                content = str(block.get("content", "") or block.get("text", ""))
                if "Image upload fails" in content and "(RESOLVED)" in content:
                    resolved_found = True
                    break
    
        if not resolved_found:
            errors.append("[X] Updated todo with '(RESOLVED)' suffix not found")
        else:
            checks_passed.append("[C] Updated todo with '(RESOLVED)' suffix found")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

    # -----------------------------------------------------------------------------
    # add-design-system-component-guidelines-v2
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_add_design_system_component_guidelines(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Task: Add Component Guidelines section after Typography.
    
    Validates:
    1. "🧩 Component Guidelines" heading_2 after Typography
    2. Three subsections (Buttons, Forms, Navigation)
    3. CSS code block, blue callout, numbered list
    4. Quote block with accurate heading_2 count
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    # 1. Find Design System page
    try:
        page_results = final_state_backend.query({
            "collection": "pages",
            "filter": {"title": "Design System"}
        })
    
        if not page_results:
            errors.append("[X] Design System page not found")
        else:
            checks_passed.append("[C] Design System page found")
    
        page = page_results[0]
        # Query blocks collection for this page
        all_blocks = final_state_backend.query({
            "collection": "blocks",
            "filter": {"pageId": page.get("_id")}
        })
    
        # 2. Check for "🧩 Component Guidelines" heading_2
        guidelines_idx = None
        for i, block in enumerate(all_blocks):
            if block.get("type") in ["heading2", "heading_2"]:
                content = str(block.get("content", "") or block.get("text", ""))
                if "🧩" in content and "Component Guidelines" in content:
                    guidelines_idx = i
                    break
    
        if guidelines_idx is None:
            errors.append("[X] '🧩 Component Guidelines' heading not found")
        else:
            checks_passed.append("[C] '🧩 Component Guidelines' heading found")
    
        # 3. Check for three subsections
        subsections = {"Buttons": False, "Forms": False, "Navigation": False}
    
        for i in range(guidelines_idx, len(all_blocks)):
            if all_blocks[i].get("type") in ["heading3", "heading_3"]:
                content = str(all_blocks[i].get("content", "") or all_blocks[i].get("text", ""))
                if "🔘" in content and "Buttons" in content:
                    subsections["Buttons"] = True
                elif "📝" in content and "Forms" in content:
                    subsections["Forms"] = True
                elif "🗂" in content and "Navigation" in content:
                    subsections["Navigation"] = True
    
        if not all(subsections.values()):
            missing = [k for k, v in subsections.items() if not v]
            errors.append(f"[X] Missing subsections: {', '.join(missing)}")
        else:
            checks_passed.append(f"[C] has subsections")
    
        # 4. Check for CSS code block
        css_found = False
        for block in all_blocks:
            if block.get("type") == "code":
                lang = block.get("properties", {}).get("language", "")
                content = str(block.get("content", "") or block.get("text", ""))
                if "css" in lang.lower() and ".btn-primary" in content:
                    css_found = True
                    break
    
        if not css_found:
            errors.append("[X] CSS code block with .btn-primary not found")
        else:
            checks_passed.append("[C] CSS code block with .btn-primary found")
    
        # 5. Check for blue callout
        blue_callout_found = False
        for block in all_blocks:
            if block.get("type") == "callout":
                bg = block.get("properties", {}).get("backgroundColor", "")
                content = str(block.get("content", "") or block.get("text", ""))
                if "blue" in bg.lower() and "form inputs" in content.lower():
                    blue_callout_found = True
                    break
    
        if not blue_callout_found:
            errors.append("[X] Blue callout about form inputs not found")
        else:
            checks_passed.append("[C] Blue callout about form inputs found")
    
        # 6. Check for numbered list
        numbered_items = sum(1 for block in all_blocks
                            if block.get("type") in ["numbered_list_item", "numberedListItem", "numberedList"])
    
        if numbered_items < 3:
            errors.append(f"[X] Expected at least 3 numbered list items, found {numbered_items}")
        else:
            checks_passed.append(f"[C] Found at least 3 numbered list items ({numbered_items})")
    
        # 7. Count heading_2 blocks and verify quote
        h2_count = sum(1 for block in all_blocks
                       if block.get("type") in ["heading2", "heading_2"])
    
        quote_found = False
        for block in all_blocks:
            if block.get("type") == "quote":
                content = str(block.get("content", "") or block.get("text", ""))
                if "design system contains" in content.lower() and "sections" in content.lower():
                    quote_found = True
                    break
    
        if not quote_found:
            errors.append("[X] Quote block with section count not found")
        else:
            checks_passed.append("[C] Quote block with section count found")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

    # -----------------------------------------------------------------------------
    # reorganize-onboarding-guide-h3-sections-v2
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_reorganize_onboarding_guide_h3_sections(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Task: Move all heading_3 sections after heading_2 sections, add Content Structure.
    
    Validates:
    1. "🔄 Content Structure" heading_2 at beginning
    2. Blue callout with 📋 icon
    3. Paragraph with accurate counts
    4. All heading_3 blocks appear after all heading_2 blocks
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    # 1. Find Onboarding Guide page
    try:
        page_results = final_state_backend.query({
            "collection": "pages",
            "filter": {"title": "Onboarding Guide"}
        })
    
        if not page_results:
            errors.append("[X] Onboarding Guide page not found")
        else:
            checks_passed.append("[C] Onboarding Guide page found")
    
        page = page_results[0]
        # Query blocks collection for this page
        all_blocks = final_state_backend.query({
            "collection": "blocks",
            "filter": {"pageId": page.get("_id")}
        })
    
        # 2. Check for "🔄 Content Structure" heading_2 near beginning
        structure_idx = None
        for i, block in enumerate(all_blocks[:20]):
            if block.get("type") in ["heading2", "heading_2"]:
                content = str(block.get("content", "") or block.get("text", ""))
                if "🔄" in content and "Content Structure" in content:
                    structure_idx = i
                    break
    
        if structure_idx is None:
            errors.append("[X] '🔄 Content Structure' heading not found at beginning")
        else:
            checks_passed.append("[C] '🔄 Content Structure' heading found at beginning")
    
        # 3. Verify blue callout with 📋 icon
        blue_callout_found = False
        for i in range(structure_idx + 1, min(structure_idx + 5, len(all_blocks))):
            if all_blocks[i].get("type") == "callout":
                bg = all_blocks[i].get("properties", {}).get("backgroundColor", "")
                icon = all_blocks[i].get("properties", {}).get("icon", "")
                content = str(all_blocks[i].get("content", "") or all_blocks[i].get("text", ""))
                if "blue" in bg.lower() and "📋" in icon and "reorganized" in content.lower():
                    blue_callout_found = True
                    break
    
        if not blue_callout_found:
            errors.append("[X] Blue callout with 📋 icon not found")
        else:
            checks_passed.append("[C] Blue callout with 📋 icon found")
    
        # 4. Count heading types and total blocks
        h2_count = sum(1 for block in all_blocks if block.get("type") in ["heading2", "heading_2"])
        h3_count = sum(1 for block in all_blocks if block.get("type") in ["heading3", "heading_3"])
        total_blocks = len(all_blocks)
    
        # 5. Verify paragraph with counts
        count_paragraph_found = False
        for block in all_blocks:
            if block.get("type") == "paragraph":
                content = str(block.get("content", "") or block.get("text", ""))
                if "Structure:" in content and "primary sections" in content and "subsections" in content:
                    count_paragraph_found = True
                    break
    
        if not count_paragraph_found:
            errors.append("[X] Paragraph with structure counts not found")
        else:
            checks_passed.append("[C] Paragraph with structure counts found")
    
        # 6. Verify reorganization (all H3 should appear after all H2, except Content Structure)
        h2_positions = [i for i, block in enumerate(all_blocks) if block.get("type") in ["heading2", "heading_2"]]
        h3_positions = [i for i, block in enumerate(all_blocks) if block.get("type") in ["heading3", "heading_3"]]
    
        if h2_positions and h3_positions:
            last_h2 = max(h2_positions)
            first_h3 = min(h3_positions)
            # H3s should generally come after H2s (with some flexibility)
            # Just check that some reorganization happened
            pass
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

    # -----------------------------------------------------------------------------
    # create-workspace-navigation-guide-v2
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_create_workspace_navigation_guide(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Task: Create Workspace Navigation Guide at root listing page hierarchies.
    
    Validates:
    1. Page exists at root in workspace-1
    2. "🗺️ Workspace Navigation Guide" heading_1
    3. "📂 Page Hierarchy" heading_2
    4. heading_3 for each top-level page with children
    5. Blue callout with accurate statistics
    6. Notion Help bookmark
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    # 1. Verify Workspace Navigation Guide exists at root
    # Use regex for the nav guide page (avoids text index timing issues)
    try:
        nav_guide_results = final_state_backend.query({
            "collection": "pages",
            "filter": {"title": {"$regex": "Workspace Navigation Guide"}}
        })
    
        nav_guide_page = None
        for page in nav_guide_results:
            title = page.get("title", "")
            if "Workspace Navigation Guide" in title:
                if not page.get("parentId"):  # Root level
                    nav_guide_page = page
                    break
    
        if not nav_guide_page:
            errors.append("[X] Workspace Navigation Guide page not found at root level")
        else:
            checks_passed.append("[C] Workspace Navigation Guide page found at root level")
    
        nav_blocks = final_state_backend.query({
            "collection": "blocks",
            "filter": {"pageId": nav_guide_page.get("_id")}
        })
    
        # 2. Check heading_1
        h1_found = False
        for block in nav_blocks:
            if block.get("type") in ["heading1", "heading_1"]:
                content = str(block.get("content", "") or block.get("text", ""))
                if "🗺" in content and "Workspace Navigation Guide" in content:
                    h1_found = True
                    break
    
        if not h1_found:
            errors.append("[X] '🗺️ Workspace Navigation Guide' heading_1 not found")
        else:
            checks_passed.append("[C] '🗺️ Workspace Navigation Guide' heading_1 found")
    
        # 3. Check for "📂 Page Hierarchy" heading_2
        hierarchy_found = False
        for block in nav_blocks:
            if block.get("type") in ["heading2", "heading_2"]:
                content = str(block.get("content", "") or block.get("text", ""))
                if "📂" in content and "Page Hierarchy" in content:
                    hierarchy_found = True
                    break
    
        if not hierarchy_found:
            errors.append("[X] '📂 Page Hierarchy' heading not found")
        else:
            checks_passed.append("[C] '📂 Page Hierarchy' heading found")
    
        # 4. Find top-level pages with children (optimized with MongoDB filters)
        # Query only top-level pages (no parent)
        top_level_pages = final_state_backend.query({
            "collection": "pages",
            "filter": {
                "$or": [
                    {"parentId": {"$exists": False}},
                    {"parentId": None}
                ]
            }
        })
    
        # For each parent, query only its children
        pages_with_children = []
        for page in top_level_pages:
            children = final_state_backend.query({
                "collection": "pages",
                "filter": {"parentId": page.get("_id")}
            })
            if children:
                pages_with_children.append((page, len(children)))
    
        # 5. Check for heading_3 entries
        h3_count = sum(1 for block in nav_blocks if block.get("type") in ["heading3", "heading_3"])
    
        if h3_count < min(len(pages_with_children), 2):
            errors.append("[X] Not enough heading_3 entries for parent pages")
        else:
            checks_passed.append("[C] enough heading_3 entries for parent pages")
    
        # 5b. Check for numbered list items showing children
        numbered_items = sum(1 for block in nav_blocks
                            if block.get("type") in ["numbered_list_item", "numberedListItem", "numberedList", "numbered_list"])
    
        if numbered_items < min(sum(count for _, count in pages_with_children), 2):
            errors.append("[X] Numbered list items for child pages not found")
        else:
            checks_passed.append("[C] Numbered list items for child pages found")
    
        # 6. Check for "📊 Workspace Statistics" heading_2
        stats_found = False
        for block in nav_blocks:
            if block.get("type") in ["heading2", "heading_2"]:
                content = str(block.get("content", "") or block.get("text", ""))
                if "📊" in content and "Workspace Statistics" in content:
                    stats_found = True
                    break
    
        if not stats_found:
            errors.append("[X] '📊 Workspace Statistics' heading not found")
        else:
            checks_passed.append("[C] '📊 Workspace Statistics' heading found")
    
        # 7. Verify blue callout
        blue_callout_found = False
        for block in nav_blocks:
            if block.get("type") == "callout":
                bg = block.get("properties", {}).get("backgroundColor", "")
                content = str(block.get("content", "") or block.get("text", ""))
                if "blue" in bg.lower() and "workspace contains" in content.lower():
                    blue_callout_found = True
                    break
    
        if not blue_callout_found:
            errors.append("[X] Blue callout with workspace statistics not found")
        else:
            checks_passed.append("[C] Blue callout with workspace statistics found")
    
        # 8. Verify Notion Help bookmark
        bookmark_found = False
        for block in nav_blocks:
            if block.get("type") == "bookmark":
                url = str(block.get("properties", {}).get("url", ""))
                if "notion.so/help" in url:
                    bookmark_found = True
                    break
    
        if not bookmark_found:
            errors.append("[X] Notion Help bookmark not found")
        else:
            checks_passed.append("[C] Notion Help bookmark found")
    
        total_subpages = sum(count for _, count in pages_with_children)
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

    # -----------------------------------------------------------------------------
    # create-q1-sprint-retrospective-analysis-v2
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_create_q1_sprint_retrospective_analysis(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Task: Create Q1 Sprint Retrospective Analysis as child of Team Retrospective.
    
    Validates:
    1. Page exists as child with correct title
    2. "🎯 Sprint Goals vs Outcomes" heading_2
    3. "✅ Action Items Status" heading_2
    4. Green callout showing 100% completion
    5. "🔄 Continuous Improvement" with exact quote
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    # 1. Find Team Retrospective page
    try:
        retro_results = final_state_backend.query({
            "collection": "pages",
            "filter": {"title": "Team Retrospective"}
        })
    
        if not retro_results:
            errors.append("[X] Team Retrospective page not found")
        else:
            checks_passed.append("[C] Team Retrospective page found")
    
        retro_page = retro_results[0]
        retro_id = retro_page.get("_id")
    
        # 2. Verify Q1 Sprint Retrospective Analysis exists as child
        child_results = final_state_backend.query({
            "collection": "pages",
            "filter": {"parentId": retro_id}
        })
    
        analysis_page = None
        for page in child_results:
            if "Q1 Sprint Retrospective Analysis" in page.get("title", ""):
                analysis_page = page
                break
    
        if not analysis_page:
            errors.append("[X] 'Q1 Sprint Retrospective Analysis' not found as child")
        else:
            checks_passed.append("[C] 'Q1 Sprint Retrospective Analysis' found as child")
    
        analysis_blocks = final_state_backend.query({
            "collection": "blocks",
            "filter": {"pageId": analysis_page.get("_id")}
        })
    
        # 3. Check heading_1
        h1_found = False
        for block in analysis_blocks:
            if block.get("type") in ["heading1", "heading_1"]:
                content = str(block.get("content", "") or block.get("text", ""))
                if "📊" in content and "Q1 Sprint Retrospective Analysis" in content:
                    h1_found = True
                    break
    
        if not h1_found:
            errors.append("[X] '📊 Q1 Sprint Retrospective Analysis' heading_1 not found")
        else:
            checks_passed.append("[C] '📊 Q1 Sprint Retrospective Analysis' heading_1 found")
    
        # 4. Check for "🎯 Sprint Goals vs Outcomes" heading_2
        goals_found = False
        for block in analysis_blocks:
            if block.get("type") in ["heading2", "heading_2"]:
                content = str(block.get("content", "") or block.get("text", ""))
                if "🎯" in content and "Sprint Goals vs Outcomes" in content:
                    goals_found = True
                    break
    
        if not goals_found:
            errors.append("[X] '🎯 Sprint Goals vs Outcomes' heading not found")
        else:
            checks_passed.append("[C] '🎯 Sprint Goals vs Outcomes' heading found")
    
        # 5. Check for "✅ Action Items Status" heading_2
        actions_found = False
        for block in analysis_blocks:
            if block.get("type") in ["heading2", "heading_2"]:
                content = str(block.get("content", "") or block.get("text", ""))
                if "✅" in content and "Action Items Status" in content:
                    actions_found = True
                    break
    
        if not actions_found:
            errors.append("[X] '✅ Action Items Status' heading not found")
        else:
            checks_passed.append("[C] '✅ Action Items Status' heading found")
    
        # 6. Check for "📈 Key Insights" with green callout
        insights_found = False
        green_callout_found = False
    
        for block in analysis_blocks:
            if block.get("type") in ["heading2", "heading_2"]:
                content = str(block.get("content", "") or block.get("text", ""))
                if "📈" in content and "Key Insights" in content:
                    insights_found = True
        
            if block.get("type") == "callout":
                bg = block.get("properties", {}).get("backgroundColor", "")
                icon = block.get("properties", {}).get("icon", "")
                content = str(block.get("content", "") or block.get("text", ""))
                if "green" in bg.lower() and "💡" in icon and "100%" in content:
                    green_callout_found = True
    
        if not insights_found:
            errors.append("[X] '📈 Key Insights' heading not found")
        else:
            checks_passed.append("[C] '📈 Key Insights' heading found")
    
        if not green_callout_found:
            errors.append("[X] Green callout with 100% completion not found")
        else:
            checks_passed.append("[C] Green callout with 100% completion found")
    
        # 7. Check for "🔄 Continuous Improvement" heading_2
        improvement_found = False
        for block in analysis_blocks:
            if block.get("type") in ["heading2", "heading_2"]:
                content = str(block.get("content", "") or block.get("text", ""))
                if "🔄" in content and "Continuous Improvement" in content:
                    improvement_found = True
                    break
    
        if not improvement_found:
            errors.append("[X] '🔄 Continuous Improvement' heading not found")
        else:
            checks_passed.append("[C] '🔄 Continuous Improvement' heading found")
    
        # 8. Check for quote
        quote_found = False
        for block in analysis_blocks:
            if block.get("type") == "quote":
                content = str(block.get("content", "") or block.get("text", ""))
                if "Continuous improvement" in content and "delayed perfection" in content:
                    quote_found = True
                    break
    
        if not quote_found:
            errors.append("[X] Quote about continuous improvement not found")
        else:
            checks_passed.append("[C] Quote about continuous improvement found")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

    # -----------------------------------------------------------------------------
    # add-product-roadmap-image-priorities-milestones-v2
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_add_product_roadmap_image_priorities_milestones(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Task: Add image before quote, insert priority, add purple callout, add Quarterly Milestones.
    
    Validates:
    1. Image block before quote block
    2. Strategic Priorities has 4 items with API item at position 2
    3. Purple callout with 🎯 icon
    4. "📅 Quarterly Milestones" heading_2 with divider
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    # 1. Find 2024 Product Roadmap page (titled "Project Roadmap")
    try:
        page_results = final_state_backend.query({
            "collection": "pages",
            "filter": {"title": "Project Roadmap"}
        })
    
        if not page_results:
            errors.append("[X] Project Roadmap page not found")
        else:
            checks_passed.append("[C] Project Roadmap page found")
    
        page = page_results[0]
        # Query blocks collection for this page
        all_blocks = final_state_backend.query({
            "collection": "blocks",
            "filter": {"pageId": page.get("_id")}
        })
    
        # 2. Find quote block
        quote_idx = None
        for i, block in enumerate(all_blocks):
            if block.get("type") == "quote":
                content = str(block.get("content", "") or block.get("text", ""))
                if "predict" in content.lower():
                    quote_idx = i
                    break
    
        if quote_idx is None:
            errors.append("[X] Quote block not found")
        else:
            checks_passed.append("[C] Quote block found")
    
        # 3. Verify image block before quote
        image_found = False
        if quote_idx > 0:
            for i in range(max(0, quote_idx - 3), quote_idx):
                if all_blocks[i].get("type") == "image":
                    url = str(all_blocks[i].get("properties", {}).get("url", ""))
                    if "roadmap-banner" in url.lower():
                        image_found = True
                        break
    
        if not image_found:
            errors.append("[X] Image block not found before quote")
        else:
            checks_passed.append("[C] Image block found before quote")
    
        # 4. Find Strategic Priorities section and count bullets
        priority_bullets = []
        in_priorities = False
    
        for i, block in enumerate(all_blocks):
            if block.get("type") in ["heading2", "heading_2", "heading3", "heading_3"]:
                content = str(block.get("content", "") or block.get("text", ""))
                if "Strategic Priorities" in content:
                    in_priorities = True
                elif in_priorities and block.get("type") in ["heading2", "heading_2", "heading3", "heading_3"]:
                    break
            elif in_priorities and block.get("type") in ["bulleted_list_item", "bulletedListItem", "bulletedList"]:
                priority_bullets.append(str(block.get("content", "") or block.get("text", "")))
    
        if len(priority_bullets) < 4:
            errors.append(f"[X] Expected 4 Strategic Priorities, found {len(priority_bullets)}")
        else:
            checks_passed.append(f"[C] Found 4 Strategic Priorities as expected")
    
        # Check if API item is at position 2
        api_at_position_2 = "API" in priority_bullets[1] if len(priority_bullets) > 1 else False
    
        if not api_at_position_2:
            errors.append("[X] API priority item not at position 2")
        else:
            checks_passed.append("[C] API priority item at position 2")
    
        # 5. Verify purple callout
        purple_callout_found = False
        for block in all_blocks:
            if block.get("type") == "callout":
                bg = block.get("properties", {}).get("backgroundColor", "")
                icon = block.get("properties", {}).get("icon", "")
                content = str(block.get("content", "") or block.get("text", ""))
                if "purple" in bg.lower() and "🎯" in icon and "reviewed monthly" in content.lower():
                    purple_callout_found = True
                    break
    
        if not purple_callout_found:
            errors.append("[X] Purple callout with 🎯 icon not found")
        else:
            checks_passed.append("[C] Purple callout with 🎯 icon found")
    
        # 6. Check for "📅 Quarterly Milestones" heading_2
        milestones_found = False
        for block in all_blocks:
            if block.get("type") in ["heading2", "heading_2"]:
                content = str(block.get("content", "") or block.get("text", ""))
                if "📅" in content and "Quarterly Milestones" in content:
                    milestones_found = True
                    break
    
        if not milestones_found:
            errors.append("[X] '📅 Quarterly Milestones' heading not found")
        else:
            checks_passed.append("[C] '📅 Quarterly Milestones' heading found")
    
        # 7. Check for divider
        divider_found = any(block.get("type") == "divider" for block in all_blocks)
    
        if not divider_found:
            errors.append("[X] Divider block not found")
        else:
            checks_passed.append("[C] Divider block found")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

    # -----------------------------------------------------------------------------
    # add-getting-started-conditional-callouts-v2
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_add_getting_started_conditional_callouts(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Task: Add conditional callouts below each unchecked todo based on keywords.
    
    Validates:
    1. Green callouts with 📝 icon for "page" todos
    2. Blue callouts with 👥 icon for "share" todos
    3. Yellow callouts with 💡 icon for other unchecked todos
    4. No callouts under checked todos
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    # 1. Find Getting Started page
    try:
        page_results = final_state_backend.query({
            "collection": "pages",
            "filter": {"title": "Getting Started"}
        })
    
        if not page_results:
            errors.append("[X] Getting Started page not found")
        else:
            checks_passed.append("[C] Getting Started page found")
    
        page = page_results[0]
        # Query blocks collection for this page
        all_blocks = final_state_backend.query({
            "collection": "blocks",
            "filter": {"pageId": page.get("_id")}
        })
    
        # 2. Count callouts by type
        green_callouts = 0
        blue_callouts = 0
        yellow_callouts = 0
    
        # 3. Analyze todo-callout pairs
        for i, block in enumerate(all_blocks):
            if block.get("type") == "todo":
                todo_content = str(block.get("content", "") or block.get("text", ""))
                checked = block.get("properties", {}).get("checked", False)
            
                # Check if next block is a callout
                if i + 1 < len(all_blocks) and all_blocks[i + 1].get("type") == "callout":
                    callout = all_blocks[i + 1]
                    bg = callout.get("properties", {}).get("backgroundColor", "")
                    icon = callout.get("properties", {}).get("icon", "")
                
                    if not checked:
                        # Unchecked todo should have callout
                        # Check "share" first as it's more specific than "page"
                        if "share" in todo_content.lower():
                            if "blue" in bg.lower() and "👥" in icon:
                                blue_callouts += 1
                        elif "page" in todo_content.lower():
                            if "green" in bg.lower() and "📝" in icon:
                                green_callouts += 1
                        else:
                            if "yellow" in bg.lower() and "💡" in icon:
                                yellow_callouts += 1
                    else:
                        # Checked todo should NOT have callout
                        errors.append("[X] Callout found under checked todo (should not exist)")
    
        total_callouts = green_callouts + blue_callouts + yellow_callouts
    
        if total_callouts < 2:
            errors.append(f"[X] Expected at least 2 conditional callouts, found {total_callouts}")
        else:
            checks_passed.append(f"[C] Found at least 2 conditional callouts ({total_callouts})")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

    # -----------------------------------------------------------------------------
    # add-engineering-wiki-dev-setup-security-v2
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_add_engineering_wiki_dev_setup_security(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Task: Insert orange callout and Security Checklist in Development Setup section.
    
    Validates:
    1. Orange callout with 💡 icon after "Start the development server"
    2. "🔒 Security Checklist" heading_3
    3. 3 unchecked todos with exact text
    4. "Environment Variables" heading_3 still exists after
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    # 1. Find Engineering Wiki page
    try:
        page_results = final_state_backend.query({
            "collection": "pages",
            "filter": {"title": "Engineering Wiki"}
        })
    
        if not page_results:
            errors.append("[X] Engineering Wiki page not found")
        else:
            checks_passed.append("[C] Engineering Wiki page found")
    
        page = page_results[0]
        # Query blocks collection for this page
        all_blocks = final_state_backend.query({
            "collection": "blocks",
            "filter": {"pageId": page.get("_id")}
        })
    
        # 2. Find Development Setup section
        dev_setup_idx = None
        for i, block in enumerate(all_blocks):
            if block.get("type") in ["heading2", "heading_2", "heading3", "heading_3"]:
                content = str(block.get("content", "") or block.get("text", ""))
                if "Development Setup" in content:
                    dev_setup_idx = i
                    break
    
        if dev_setup_idx is None:
            errors.append("[X] Development Setup section not found")
        else:
            checks_passed.append("[C] Development Setup section found")
    
        # 3. Check for orange callout
        orange_callout_found = False
        for i in range(dev_setup_idx, min(dev_setup_idx + 30, len(all_blocks))):
            if all_blocks[i].get("type") == "callout":
                bg = all_blocks[i].get("properties", {}).get("backgroundColor", "")
                icon = all_blocks[i].get("properties", {}).get("icon", "")
                content = str(all_blocks[i].get("content", "") or all_blocks[i].get("text", ""))
                if "orange" in bg.lower() and "💡" in icon and "hot reloading" in content.lower():
                    orange_callout_found = True
                    break
    
        if not orange_callout_found:
            errors.append("[X] Orange callout with 💡 icon not found")
        else:
            checks_passed.append("[C] Orange callout with 💡 icon found")
    
        # 4. Check for "🔒 Security Checklist" heading_3
        security_idx = None
        for i in range(dev_setup_idx, len(all_blocks)):
            if all_blocks[i].get("type") in ["heading3", "heading_3"]:
                content = str(all_blocks[i].get("content", "") or all_blocks[i].get("text", ""))
                if "🔒" in content and "Security Checklist" in content:
                    security_idx = i
                    break
    
        if security_idx is None:
            errors.append("[X] '🔒 Security Checklist' heading not found")
        else:
            checks_passed.append("[C] '🔒 Security Checklist' heading found")
    
        # 5. Check for 3 unchecked todos
        expected_todos = [
            "API keys",
            "two-factor authentication",
            "security audit"
        ]
    
        found_todos = 0
        for i in range(security_idx + 1, min(security_idx + 10, len(all_blocks))):
            if all_blocks[i].get("type") == "todo":
                content = str(all_blocks[i].get("content", "") or all_blocks[i].get("text", ""))
                checked = all_blocks[i].get("properties", {}).get("checked", False)
                if not checked and any(expected in content for expected in expected_todos):
                    found_todos += 1
    
        if found_todos < 3:
            errors.append(f"[X] Expected 3 unchecked security todos, found {found_todos}")
        else:
            checks_passed.append(f"[C] Found 3 unchecked security todos as expected")
    
        # 6. Verify Environment Variables heading still exists
        env_vars_found = False
        for i in range(security_idx, len(all_blocks)):
            if all_blocks[i].get("type") in ["heading3", "heading_3"]:
                content = str(all_blocks[i].get("content", "") or all_blocks[i].get("text", ""))
                if "Environment Variables" in content:
                    env_vars_found = True
                    break
    
        if not env_vars_found:
            errors.append("[X] 'Environment Variables' heading_3 not found after new content")
        else:
            checks_passed.append("[C] 'Environment Variables' heading_3 found after new content")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

    # -----------------------------------------------------------------------------
    # reorganize-handbook-swap-values-benefits-add-office-hours-v2
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_reorganize_handbook_swap_values_benefits_add_office_hours(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Task: Swap Our Values and Benefits sections, add Office Hours in Work Policies.
    
    Validates:
    1. Benefits section appears where Our Values was
    2. Our Values section appears where Benefits was
    3. "🏢 Office Hours" heading_3 in Work Policies
    4. Paragraph with exact text about core hours
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    # 1. Find Company Handbook page
    try:
        page_results = final_state_backend.query({
            "collection": "pages",
            "filter": {"title": "Company Handbook"}
        })
    
        if not page_results:
            errors.append("[X] Company Handbook page not found")
        else:
            checks_passed.append("[C] Company Handbook page found")
    
        page = page_results[0]
        # Query blocks collection for this page
        all_blocks = final_state_backend.query({
            "collection": "blocks",
            "filter": {"pageId": page.get("_id")}
        })
    
        # 2. Find section positions
        values_idx = None
        benefits_idx = None
    
        for i, block in enumerate(all_blocks):
            if block.get("type") in ["heading2", "heading_2"]:
                content = str(block.get("content", "") or block.get("text", ""))
                if "Our Values" in content:
                    values_idx = i
                elif "Benefits" in content:
                    benefits_idx = i
    
        if values_idx is None:
            errors.append("[X] 'Our Values' section not found")
        else:
            checks_passed.append("[C] 'Our Values' section found")
        if benefits_idx is None:
            errors.append("[X] 'Benefits' section not found")
        else:
            checks_passed.append("[C] 'Benefits' section found")
    
        # 3. Verify sections are swapped (Benefits should come before Our Values now)
        if benefits_idx >= values_idx:
            errors.append("[X] Sections not swapped: Benefits should appear before Our Values")
        else:
            checks_passed.append("[C] Sections swapped: Benefits should appear before Our Values")
    
        # 4. Find Work Policies section
        work_policies_idx = None
        for i, block in enumerate(all_blocks):
            if block.get("type") in ["heading2", "heading_2"]:
                content = str(block.get("content", "") or block.get("text", ""))
                if "Work Policies" in content:
                    work_policies_idx = i
                    break
    
        if work_policies_idx is None:
            errors.append("[X] 'Work Policies' section not found")
        else:
            checks_passed.append("[C] 'Work Policies' section found")
    
        # 5. Find "Remote Work" heading_3
        remote_work_idx = None
        for i in range(work_policies_idx, len(all_blocks)):
            if all_blocks[i].get("type") in ["heading3", "heading_3"]:
                content = str(all_blocks[i].get("content", "") or all_blocks[i].get("text", ""))
                if "Remote Work" in content:
                    remote_work_idx = i
                    break
    
        if remote_work_idx is None:
            errors.append("[X] 'Remote Work' subsection not found in Work Policies")
        else:
            checks_passed.append("[C] 'Remote Work' subsection found in Work Policies")
    
        # 6. Find "Time Off" heading_3
        time_off_idx = None
        for i in range(work_policies_idx, len(all_blocks)):
            if all_blocks[i].get("type") in ["heading3", "heading_3"]:
                content = str(all_blocks[i].get("content", "") or all_blocks[i].get("text", ""))
                if "Time Off" in content:
                    time_off_idx = i
                    break
    
        if time_off_idx is None:
            errors.append("[X] 'Time Off' subsection not found in Work Policies")
        else:
            checks_passed.append("[C] 'Time Off' subsection found in Work Policies")
    
        # 7. Check for "🏢 Office Hours" heading_3 between Remote Work and Time Off
        office_hours_idx = None
        for i in range(remote_work_idx + 1, time_off_idx):
            if all_blocks[i].get("type") in ["heading3", "heading_3"]:
                content = str(all_blocks[i].get("content", "") or all_blocks[i].get("text", ""))
                # Accept various building emojis due to potential encoding variations
                if any(emoji in content for emoji in ["🏢", "🏬", "🏛", "🏦"]) and "Office Hours" in content:
                    office_hours_idx = i
                    break
    
        if office_hours_idx is None:
            errors.append("[X] '🏢 Office Hours' heading not found between Remote Work and Time Off subsections")
        else:
            checks_passed.append("[C] '🏢 Office Hours' heading found between Remote Work and Time Off subsections")
    
        # 8. Verify paragraph with exact text about core hours
        paragraph_found = False
        for i in range(office_hours_idx + 1, min(office_hours_idx + 5, len(all_blocks))):
            if all_blocks[i].get("type") == "paragraph":
                content = str(all_blocks[i].get("content", "") or all_blocks[i].get("text", ""))
                if "Core hours are 10 AM - 3 PM" in content and "local timezone" in content:
                    paragraph_found = True
                    break
    
        if not paragraph_found:
            errors.append("[X] Paragraph with core hours text not found after Office Hours heading")
        else:
            checks_passed.append("[C] Paragraph with core hours text found after Office Hours heading")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

    # -----------------------------------------------------------------------------
    # company-handbook-quick-navigation-v2
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_company_handbook_quick_navigation(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Task: Analyze Company Handbook structure, swap Benefits and Compensation sections, 
    add Quick Navigation section with subsection counts.
    
    Validates:
    1. Benefits and Compensation sections (if they exist) have swapped positions
    2. '📌 Quick Navigation' heading2 appears immediately after the main heading1
    3. Bulleted list contains one item per heading2 section with accurate subsection counts
    4. Divider exists after Quick Navigation section
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    # Find Company Handbook page
    try:
        page_results = final_state_backend.query({
            "collection": "pages",
            "filter": {"title": "Company Handbook"}
        })
    
        if not page_results:
            errors.append("[X] Company Handbook page not found")
        else:
            checks_passed.append("[C] Company Handbook page found")
    
        page = page_results[0]
        # Query blocks collection for this page
        all_blocks = final_state_backend.query({
            "collection": "blocks",
            "filter": {"pageId": page.get("_id")}
        })
    
        if not all_blocks:
            errors.append("[X] No blocks found in Company Handbook")
        else:
            checks_passed.append("[C] blocks found in Company Handbook")
    
        # Find heading1, heading2, and heading3 blocks
        heading1_idx = None
        heading2_blocks = []  # (index, title)
        heading3_counts = {}  # section_name -> count of heading3s
        benefits_idx = None
        compensation_idx = None
        quick_nav_idx = None
    
        for i, block in enumerate(all_blocks):
            block_type = block.get("type", "")
            content = str(block.get("content", "") or block.get("text", ""))
        
            if block_type in ["heading1", "heading_1"]:
                if heading1_idx is None:  # First heading1
                    heading1_idx = i
            elif block_type in ["heading2", "heading_2"]:
                heading2_blocks.append((i, content))
                heading3_counts[content] = 0
            
                # Check for Benefits and Compensation
                if "Benefits" in content and "Compensation" not in content:
                    benefits_idx = i
                elif "Compensation" in content and "Benefits" not in content:
                    compensation_idx = i
            
                # Check for Quick Navigation
                if "📌" in content and "Quick Navigation" in content:
                    quick_nav_idx = i
    
        # Count heading3 blocks for each section
        current_section = None
        for i, block in enumerate(all_blocks):
            block_type = block.get("type", "")
            content = str(block.get("content", "") or block.get("text", ""))
        
            if block_type in ["heading2", "heading_2"]:
                current_section = content
            elif block_type in ["heading3", "heading_3"] and current_section:
                heading3_counts[current_section] = heading3_counts.get(current_section, 0) + 1
    
        # Check 1: If Benefits and Compensation exist, ensure they're swapped
        # This means Compensation should come before Benefits
        if benefits_idx is not None and compensation_idx is not None:
            if compensation_idx > benefits_idx:
                errors.append("[X] Benefits and Compensation sections were not swapped (Compensation should come before Benefits)")
            else:
                checks_passed.append("[C] Benefits and Compensation sections were swapped (Compensation should come before Benefits)")
    
        # Check 2: Quick Navigation should exist immediately after heading1
        if quick_nav_idx is None:
            errors.append("[X] '📌 Quick Navigation' heading2 not found")
        else:
            checks_passed.append("[C] '📌 Quick Navigation' heading2 found")
    
        if heading1_idx is None:
            errors.append("[X] Main heading1 not found in Company Handbook")
        else:
            checks_passed.append("[C] Main heading1 found in Company Handbook")
    
        # Quick Navigation should be the first or second block after heading1
        # (allowing for one block in between)
        if quick_nav_idx > heading1_idx + 2:
            errors.append("[X] '📌 Quick Navigation' should appear immediately after the main heading1")
        else:
            checks_passed.append("[C] '📌 Quick Navigation' should appear immediately after the main heading1")
    
        # Check 3: Bulleted list after Quick Navigation with section counts
        # Find bulleted list blocks after Quick Navigation
        bulleted_items = []
        for i in range(quick_nav_idx + 1, min(quick_nav_idx + 20, len(all_blocks))):
            block = all_blocks[i]
            block_type = block.get("type", "")
        
            # Stop at next heading
            if block_type in ["heading1", "heading_1", "heading2", "heading_2", "heading3", "heading_3"]:
                break
        
            if block_type in ["bulletedList", "bulleted_list_item"]:
                content = str(block.get("content", "") or block.get("text", ""))
                bulleted_items.append(content)
    
        if not bulleted_items:
            errors.append("[X] No bulleted list found after Quick Navigation")
        else:
            checks_passed.append("[C] bulleted list found after Quick Navigation")
    
        # Count sections (excluding Quick Navigation itself)
        sections_to_check = [(idx, title) for idx, title in heading2_blocks 
                             if "Quick Navigation" not in title]
    
        if len(bulleted_items) < len(sections_to_check):
            errors.append(f"[X] Expected {len(sections_to_check)} bulleted items for sections, found {len(bulleted_items)}")
        else:
            checks_passed.append(f"[C] Expected {len(sections_to_check)} bulleted items for sections, found {len(bulleted_items)}")
    
        # Verify bulleted items contain section names and subsection counts
        # Format: "• [Section Name] - [X] subsections"
        sections_found = 0
        for bullet in bulleted_items:
            # Check if bullet contains a section name and subsection count pattern
            if " - " in bullet and "subsection" in bullet.lower():
                sections_found += 1
            # Also accept format without explicit "subsections" text but with numbers
            elif any(section_name.strip() in bullet for _, section_name in sections_to_check):
                sections_found += 1
    
        if sections_found < len(sections_to_check):
            errors.append(f"[X] Bulleted items should contain section names with subsection counts (found {sections_found}/{len(sections_to_check)})")
        else:
            checks_passed.append(f"[C] Bulleted items should contain section names with subsection counts (found {sections_found}/{len(sections_to_check)})")
    
        # Check 4: Divider after Quick Navigation section
        divider_found = False
        for i in range(quick_nav_idx + 1, min(quick_nav_idx + 20, len(all_blocks))):
            block = all_blocks[i]
            block_type = block.get("type", "")
        
            if block_type == "divider":
                divider_found = True
                break
        
            # Stop at next heading2 (after Quick Navigation)
            if block_type in ["heading2", "heading_2"] and i != quick_nav_idx:
                break
    
        if not divider_found:
            errors.append("[X] Divider not found after Quick Navigation section")
        else:
            checks_passed.append("[C] Divider found after Quick Navigation section")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Reward Functions
# =============================================================================
def _validate_agent_duplicate_onboarding_checklist(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Task: Duplicate 'Weekly Standup Template' and customize it into a comprehensive team onboarding checklist.
    
    Validates:
    1. 'New Hire Onboarding Checklist' page exists with graduation cap icon (🎓)
    2. Page is marked as favorite
    3. Page is a child of 'Team Directory' page
    4. Page contains structured content with:
       - Callout blocks
       - Todo blocks
       - Heading blocks (heading1, heading2, or heading3)
       - Bookmark blocks
    5. Original 'Weekly Standup Template' page still exists
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Find "New Hire Onboarding Checklist" page
    try:
        onboarding_page = _find_page_by_title(final_state_backend, "New Hire Onboarding Checklist")
        if not onboarding_page:
            errors.append("[X] Page 'New Hire Onboarding Checklist' not found")
        else:
            checks_passed.append("[C] Page 'New Hire Onboarding Checklist' found")
    
        onboarding_page_id = onboarding_page.get("_id")
        if not onboarding_page_id:
            errors.append("[X] New Hire Onboarding Checklist page has no _id")
        else:
            checks_passed.append("[C] New Hire Onboarding Checklist page has _id")
    
        # 2. Check graduation cap icon (🎓)
        page_icon = onboarding_page.get("icon", "")
        if page_icon != "🎓":
            errors.append(f"[X] Page 'New Hire Onboarding Checklist' does not have graduation cap icon (🎓), found: '{page_icon}'")
        else:
            checks_passed.append(f"[C] Page 'New Hire Onboarding Checklist' has graduation cap icon (🎓), found: '{page_icon}'")
    
        # 3. Check page is marked as favorite
        if not onboarding_page.get("isFavorite", False):
            errors.append("[X] Page 'New Hire Onboarding Checklist' is not marked as favorite")
        else:
            checks_passed.append("[C] Page 'New Hire Onboarding Checklist' is marked as favorite")
    
        # 4. Find "Team Directory" page and verify parent relationship
        team_directory_page = _find_page_by_title(final_state_backend, "Team Directory")
        if not team_directory_page:
            errors.append("[X] Page 'Team Directory' not found")
        else:
            checks_passed.append("[C] Page 'Team Directory' found")
    
        team_directory_id = team_directory_page.get("_id")
        if not team_directory_id:
            errors.append("[X] Team Directory page has no _id")
        else:
            checks_passed.append("[C] Team Directory page has _id")
    
        # Check that onboarding page is a child of Team Directory
        if not _check_page_is_child_of(team_directory_page, onboarding_page):
            errors.append("[X] Page 'New Hire Onboarding Checklist' is not a child of 'Team Directory'")
        else:
            checks_passed.append("[C] Page 'New Hire Onboarding Checklist' is a child of 'Team Directory'")
    
        # 5. Validate page content structure
        blocks = _get_blocks_for_page(final_state_backend, onboarding_page_id)
    
        if not blocks:
            errors.append("[X] Page 'New Hire Onboarding Checklist' has no content blocks")
        else:
            checks_passed.append("[C] Page 'New Hire Onboarding Checklist' has content blocks")
    
        # Check for required block types
        block_types = [block.get("type") for block in blocks]
    
        has_callout = "callout" in block_types
        has_todo = "todo" in block_types
        has_heading = any(bt in block_types for bt in ["heading1", "heading2", "heading3"])
        has_bookmark = "bookmark" in block_types
    
        missing_blocks = []
        if not has_callout:
            missing_blocks.append("callout")
        if not has_todo:
            missing_blocks.append("todo")
        if not has_heading:
            missing_blocks.append("heading (heading1/heading2/heading3)")
        if not has_bookmark:
            missing_blocks.append("bookmark")
    
        if missing_blocks:
            errors.append(f"[X] Page 'New Hire Onboarding Checklist' is missing required block types: {', '.join(missing_blocks)}")
        else:
            checks_passed.append(f"[C] Page 'New Hire Onboarding Checklist' is has required block types: {', '.join(missing_blocks)}")
    
        # 6. Verify original 'Weekly Standup Template' still exists
        standup_template = _find_page_by_title(final_state_backend, "Weekly Standup Template")
        if not standup_template:
            errors.append("[X] Original 'Weekly Standup Template' page not found (may have been deleted)")
        else:
            checks_passed.append("[C] Original 'Weekly Standup Template' page found (may have been deleted)")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_agent_reorganize_project_documentation(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Task: Reorganize project documentation by finding pages with 'Project' in title,
    creating an archive page, and moving at least 3 project pages under it.
    
    Validates:
    1. 'Archive - Q4 2024' page exists with folder icon (📁)
    2. Page is marked as favorite
    3. At least 3 pages with 'Project' in title are children of the archive page
    4. Archive page contains a callout block
    5. Callout block contains information about moved items
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Find "Archive - Q4 2024" page
    try:
        archive_page = _find_page_by_title(final_state_backend, "Archive - Q4 2024")
        if not archive_page:
            errors.append("[X] Page 'Archive - Q4 2024' not found")
        else:
            checks_passed.append("[C] Page 'Archive - Q4 2024' found")
    
        archive_page_id = archive_page.get("_id")
        if not archive_page_id:
            errors.append("[X] Archive - Q4 2024 page has no _id")
        else:
            checks_passed.append("[C] Archive - Q4 2024 page has _id")
    
        # 2. Check folder icon (📁)
        page_icon = archive_page.get("icon", "")
        if page_icon != "📁":
            errors.append(f"[X] Page 'Archive - Q4 2024' does not have folder icon (📁), found: '{page_icon}'")
        else:
            checks_passed.append(f"[C] Page 'Archive - Q4 2024' has folder icon (📁), found: '{page_icon}'")
    
        # 3. Check page is marked as favorite
        if not archive_page.get("isFavorite", False):
            errors.append("[X] Page 'Archive - Q4 2024' is not marked as favorite")
        else:
            checks_passed.append("[C] Page 'Archive - Q4 2024' is marked as favorite")
    
        # 4. Find all pages with "Project" in title
        project_pages = _find_pages_by_title(final_state_backend, "project")
    
        if len(project_pages) == 0:
            errors.append("[X] No pages found with 'Project' in title")
        else:
            checks_passed.append("[C] pages found with 'Project' in title")
    
        # 5. Verify at least 3 project pages are children of the archive page
        archived_project_pages = []
        for project_page in project_pages:
            if _check_page_is_child_of(archive_page, project_page):
                archived_project_pages.append(project_page)
    
        if len(archived_project_pages) < 3:
            errors.append(f"[X] Only {len(archived_project_pages)} pages with 'Project' in title are children of 'Archive - Q4 2024', but at least 3 are required")
        else:
            checks_passed.append(f"[C] Only {len(archived_project_pages)} pages with 'Project' in title are children of 'Archive - Q4 2024', but at least 3 are required")
    
        # 6. Validate archive page has a callout block
        blocks = _get_blocks_for_page(final_state_backend, archive_page_id)
    
        if not blocks:
            errors.append("[X] Page 'Archive - Q4 2024' has no content blocks")
        else:
            checks_passed.append("[C] Page 'Archive - Q4 2024' has content blocks")
    
        # Check for callout block
        callout_blocks = [b for b in blocks if b.get("type") == "callout"]
        if not callout_blocks:
            errors.append("[X] Page 'Archive - Q4 2024' does not contain a callout block")
        else:
            checks_passed.append("[C] Page 'Archive - Q4 2024' does contains a callout block")
    
        # 7. Verify callout block contains information about moved items
        # Check if any callout block mentions the archived project pages
        callout_has_content = False
        for callout in callout_blocks:
            content = callout.get("content", "").lower()
            # Check if callout mentions at least one of the archived project pages
            for archived_page in archived_project_pages[:3]:  # Check first 3
                page_title = archived_page.get("title", "").lower()
                if page_title and page_title in content:
                    callout_has_content = True
                    break
            # Also check for common archive-related keywords
            if any(keyword in content for keyword in ["moved", "archived", "project", "list", "summary"]):
                callout_has_content = True
                break
    
        if not callout_has_content:
            errors.append("[X] Callout block in 'Archive - Q4 2024' does not appear to contain information about moved items")
        else:
            checks_passed.append("[C] Callout block in 'Archive - Q4 2024' appear to contain information about moved items")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_agent_create_learning_development_hub(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Task: Create a learning and development hub with subpages and content.
    
    Validates:
    1. 'Learning Hub' page exists with graduation cap icon (🎓)
    2. Three subpages exist under Learning Hub:
       - 'Training Materials'
       - 'Skills Assessment'
       - 'Career Development'
    3. Learning Hub contains heading1, paragraph, and numberedList blocks
    4. 'Weekly Standup Template' is found and moved under 'Training Materials'
    5. Proper 3-level hierarchy: Learning Hub -> Training Materials -> Weekly Standup Template
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Find "Learning Hub" page
    try:
        learning_hub_page = _find_page_by_title(final_state_backend, "Learning Hub")
        if not learning_hub_page:
            errors.append("[X] Page 'Learning Hub' not found")
        else:
            checks_passed.append("[C] Page 'Learning Hub' found")
    
        learning_hub_id = learning_hub_page.get("_id")
        if not learning_hub_id:
            errors.append("[X] Learning Hub page has no _id")
        else:
            checks_passed.append("[C] Learning Hub page has _id")
    
        # 2. Check graduation cap icon (🎓)
        page_icon = learning_hub_page.get("icon", "")
        if page_icon != "🎓":
            errors.append(f"[X] Page 'Learning Hub' does not have graduation cap icon (🎓), found: '{page_icon}'")
        else:
            checks_passed.append(f"[C] Page 'Learning Hub' has graduation cap icon (🎓), found: '{page_icon}'")
    
        # 3. Find and verify the three required subpages
        required_subpages = ["Training Materials", "Skills Assessment", "Career Development"]
        found_subpages = []
        missing_subpages = []
    
        for subpage_title in required_subpages:
            subpage = _find_child_by_title(final_state_backend, learning_hub_page, subpage_title)
            if subpage:
                found_subpages.append(subpage_title)
            else:
                missing_subpages.append(subpage_title)
    
        if missing_subpages:
            errors.append(f"[X] Missing required subpages under 'Learning Hub': {', '.join(missing_subpages)}")
        else:
            checks_passed.append(f"[C] has required subpages under 'Learning Hub': {', '.join(missing_subpages)}")
    
        # 4. Validate Learning Hub content blocks
        blocks = _get_blocks_for_page(final_state_backend, learning_hub_id)
    
        if not blocks:
            errors.append("[X] Page 'Learning Hub' has no content blocks")
        else:
            checks_passed.append("[C] Page 'Learning Hub' has content blocks")
    
        # Check for required block types
        block_types = [block.get("type") for block in blocks]
    
        has_heading1 = "heading1" in block_types
        has_paragraph = "paragraph" in block_types
        has_numbered_list = "numberedList" in block_types
    
        missing_blocks = []
        if not has_heading1:
            missing_blocks.append("heading1")
        if not has_paragraph:
            missing_blocks.append("paragraph")
        if not has_numbered_list:
            missing_blocks.append("numberedList")
    
        if missing_blocks:
            errors.append(f"[X] Page 'Learning Hub' is missing required block types: {', '.join(missing_blocks)}")
        else:
            checks_passed.append(f"[C] Page 'Learning Hub' is has required block types: {', '.join(missing_blocks)}")
    
        # 5. Find "Training Materials" subpage
        training_materials_page = _find_child_by_title(final_state_backend, learning_hub_page, "Training Materials")
        if not training_materials_page:
            errors.append("[X] Subpage 'Training Materials' not found under 'Learning Hub'")
        else:
            checks_passed.append("[C] Subpage 'Training Materials' found under 'Learning Hub'")
    
        training_materials_id = training_materials_page.get("_id")
        if not training_materials_id:
            errors.append("[X] Training Materials page has no _id")
        else:
            checks_passed.append("[C] Training Materials page has _id")
    
        # 6. Verify "Weekly Standup Template" is a child of "Training Materials"
        standup_template = _find_page_by_title(final_state_backend, "Weekly Standup Template")
        if not standup_template:
            errors.append("[X] Page 'Weekly Standup Template' not found")
        else:
            checks_passed.append("[C] Page 'Weekly Standup Template' found")
    
        # Check that Weekly Standup Template is a child of Training Materials
        if not _check_page_is_child_of(training_materials_page, standup_template):
            errors.append("[X] Page 'Weekly Standup Template' is not a child of 'Training Materials'")
        else:
            checks_passed.append("[C] Page 'Weekly Standup Template' is a child of 'Training Materials'")
    
        # 7. Verify proper 3-level hierarchy
        # Learning Hub -> Training Materials -> Weekly Standup Template
        standup_parent_id = standup_template.get("parentId")
        if standup_parent_id != training_materials_id:
            errors.append(f"[X] Invalid hierarchy: 'Weekly Standup Template' parent is '{standup_parent_id}', expected '{training_materials_id}' (Training Materials)")
        else:
            checks_passed.append(f"[C] valid hierarchy: 'Weekly Standup Template' parent is '{standup_parent_id}', expected '{training_materials_id}' (Training Materials)")
    
        training_parent_id = training_materials_page.get("parentId")
        if training_parent_id != learning_hub_id:
            errors.append(f"[X] Invalid hierarchy: 'Training Materials' parent is '{training_parent_id}', expected '{learning_hub_id}' (Learning Hub)")
        else:
            checks_passed.append(f"[C] valid hierarchy: 'Training Materials' parent is '{training_parent_id}', expected '{learning_hub_id}' (Learning Hub)")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_agent_create_quarterly_review_system(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Task: Organize documentation by creating a quarterly review system.
    Search for pages containing 'Q1' or 'Q2' in titles, create 'Quarterly Reviews' page
    with calendar icon, create archive sub-pages, move quarterly pages into archives,
    and add callouts, dividers, and todo checklists.
    
    Validates:
    1. 'Quarterly Reviews' page exists with calendar icon (📅)
    2. 'Q1 2024 Archive' and 'Q2 2024 Archive' sub-pages exist under Quarterly Reviews
    3. Pages with 'Q1' in title are moved to 'Q1 2024 Archive'
    4. Pages with 'Q2' in title are moved to 'Q2 2024 Archive'
    5. Each archive page contains:
       - Callout blocks with quarterly summaries
       - Divider blocks
       - Todo blocks
    6. Proper parent-child relationships are maintained
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Find "Quarterly Reviews" page
    try:
        quarterly_reviews_page = _find_page_by_title(final_state_backend, "Quarterly Reviews")
        if not quarterly_reviews_page:
            errors.append("[X] Page 'Quarterly Reviews' not found")
        else:
            checks_passed.append("[C] Page 'Quarterly Reviews' found")
    
        quarterly_reviews_id = quarterly_reviews_page.get("_id")
        if not quarterly_reviews_id:
            errors.append("[X] Quarterly Reviews page has no _id")
        else:
            checks_passed.append("[C] Quarterly Reviews page has _id")
    
        # 2. Check calendar icon (📅)
        page_icon = quarterly_reviews_page.get("icon", "")
        if page_icon != "📅":
            errors.append(f"[X] Page 'Quarterly Reviews' does not have calendar icon (📅), found: '{page_icon}'")
        else:
            checks_passed.append(f"[C] Page 'Quarterly Reviews' has calendar icon (📅), found: '{page_icon}'")
    
        # 3. Find and verify archive sub-pages
        q1_archive_page = _find_child_by_title(final_state_backend, quarterly_reviews_page, "Q1 2024 Archive")
        if not q1_archive_page:
            errors.append("[X] Subpage 'Q1 2024 Archive' not found under 'Quarterly Reviews'")
        else:
            checks_passed.append("[C] Subpage 'Q1 2024 Archive' found under 'Quarterly Reviews'")
    
        q1_archive_id = q1_archive_page.get("_id")
        if not q1_archive_id:
            errors.append("[X] Q1 2024 Archive page has no _id")
        else:
            checks_passed.append("[C] Q1 2024 Archive page has _id")
    
        q2_archive_page = _find_child_by_title(final_state_backend, quarterly_reviews_page, "Q2 2024 Archive")
        if not q2_archive_page:
            errors.append("[X] Subpage 'Q2 2024 Archive' not found under 'Quarterly Reviews'")
        else:
            checks_passed.append("[C] Subpage 'Q2 2024 Archive' found under 'Quarterly Reviews'")
    
        q2_archive_id = q2_archive_page.get("_id")
        if not q2_archive_id:
            errors.append("[X] Q2 2024 Archive page has no _id")
        else:
            checks_passed.append("[C] Q2 2024 Archive page has _id")
    
        # Verify proper parent-child relationships for archive pages
        if not _check_page_is_child_of(quarterly_reviews_page, q1_archive_page):
            errors.append("[X] Page 'Q1 2024 Archive' is not a child of 'Quarterly Reviews'")
        else:
            checks_passed.append("[C] Page 'Q1 2024 Archive' is a child of 'Quarterly Reviews'")
    
        if not _check_page_is_child_of(quarterly_reviews_page, q2_archive_page):
            errors.append("[X] Page 'Q2 2024 Archive' is not a child of 'Quarterly Reviews'")
        else:
            checks_passed.append("[C] Page 'Q2 2024 Archive' is a child of 'Quarterly Reviews'")
    
        # 4. Find pages with 'Q1' or 'Q2' in titles (excluding the archive pages)
        q1_pages_all = _find_pages_by_title(final_state_backend, "q1")
        q2_pages_all = _find_pages_by_title(final_state_backend, "q2")
        q1_pages = [p for p in q1_pages_all if p.get("_id") not in [q1_archive_id, q2_archive_id]]
        q2_pages = [p for p in q2_pages_all if p.get("_id") not in [q1_archive_id, q2_archive_id]]
    
        # 5. Verify Q1 pages are children of Q1 Archive
        archived_q1_pages = []
        for q1_page in q1_pages:
            if _check_page_is_child_of(q1_archive_page, q1_page):
                archived_q1_pages.append(q1_page)
    
        if len(q1_pages) > 0 and len(archived_q1_pages) == 0:
            errors.append(f"[X] Found {len(q1_pages)} page(s) with 'Q1' in title, but none are children of 'Q1 2024 Archive'")
        else:
            checks_passed.append(f"[C] Found {len(q1_pages)} page(s) with 'Q1' in title, but none are children of 'Q1 2024 Archive'")
    
        # 6. Verify Q2 pages are children of Q2 Archive
        archived_q2_pages = []
        for q2_page in q2_pages:
            if _check_page_is_child_of(q2_archive_page, q2_page):
                archived_q2_pages.append(q2_page)
    
        if len(q2_pages) > 0 and len(archived_q2_pages) == 0:
            errors.append(f"[X] Found {len(q2_pages)} page(s) with 'Q2' in title, but none are children of 'Q2 2024 Archive'")
        else:
            checks_passed.append(f"[C] Found {len(q2_pages)} page(s) with 'Q2' in title, but none are children of 'Q2 2024 Archive'")
    
        # 7. Validate Q1 Archive page content blocks
        q1_blocks = _get_blocks_for_page(final_state_backend, q1_archive_id)
    
        if not q1_blocks:
            errors.append("[X] Page 'Q1 2024 Archive' has no content blocks")
        else:
            checks_passed.append("[C] Page 'Q1 2024 Archive' has content blocks")
    
        q1_block_types = [block.get("type") for block in q1_blocks]
    
        has_q1_callout = "callout" in q1_block_types
        has_q1_divider = "divider" in q1_block_types
        has_q1_todo = "todo" in q1_block_types
    
        q1_missing_blocks = []
        if not has_q1_callout:
            q1_missing_blocks.append("callout")
        if not has_q1_divider:
            q1_missing_blocks.append("divider")
        if not has_q1_todo:
            q1_missing_blocks.append("todo")
    
        if q1_missing_blocks:
            errors.append(f"[X] Page 'Q1 2024 Archive' is missing required block types: {', '.join(q1_missing_blocks)}")
        else:
            checks_passed.append(f"[C] Page 'Q1 2024 Archive' is has required block types: {', '.join(q1_missing_blocks)}")
    
        # Verify callout contains quarterly summary content
        q1_callout_blocks = [b for b in q1_blocks if b.get("type") == "callout"]
        q1_callout_has_summary = False
        for callout in q1_callout_blocks:
            content = callout.get("content", "").lower()
            # Check for summary-related keywords or mentions of Q1
            if any(keyword in content for keyword in ["summary", "accomplished", "completed", "quarter", "q1", "2024", "achieved"]):
                q1_callout_has_summary = True
                break
    
        if not q1_callout_has_summary:
            errors.append("[X] Callout block in 'Q1 2024 Archive' does not appear to contain quarterly summary information")
        else:
            checks_passed.append("[C] Callout block in 'Q1 2024 Archive' appear to contain quarterly summary information")
    
        # 8. Validate Q2 Archive page content blocks
        q2_blocks = _get_blocks_for_page(final_state_backend, q2_archive_id)
    
        if not q2_blocks:
            errors.append("[X] Page 'Q2 2024 Archive' has no content blocks")
        else:
            checks_passed.append("[C] Page 'Q2 2024 Archive' has content blocks")
    
        q2_block_types = [block.get("type") for block in q2_blocks]
    
        has_q2_callout = "callout" in q2_block_types
        has_q2_divider = "divider" in q2_block_types
        has_q2_todo = "todo" in q2_block_types
    
        q2_missing_blocks = []
        if not has_q2_callout:
            q2_missing_blocks.append("callout")
        if not has_q2_divider:
            q2_missing_blocks.append("divider")
        if not has_q2_todo:
            q2_missing_blocks.append("todo")
    
        if q2_missing_blocks:
            errors.append(f"[X] Page 'Q2 2024 Archive' is missing required block types: {', '.join(q2_missing_blocks)}")
        else:
            checks_passed.append(f"[C] Page 'Q2 2024 Archive' is has required block types: {', '.join(q2_missing_blocks)}")
    
        # Verify callout contains quarterly summary content
        q2_callout_blocks = [b for b in q2_blocks if b.get("type") == "callout"]
        q2_callout_has_summary = False
        for callout in q2_callout_blocks:
            content = callout.get("content", "").lower()
            # Check for summary-related keywords or mentions of Q2
            if any(keyword in content for keyword in ["summary", "accomplished", "completed", "quarter", "q2", "2024", "achieved"]):
                q2_callout_has_summary = True
                break
    
        if not q2_callout_has_summary:
            errors.append("[X] Callout block in 'Q2 2024 Archive' does not appear to contain quarterly summary information")
        else:
            checks_passed.append("[C] Callout block in 'Q2 2024 Archive' appear to contain quarterly summary information")
    
        # Build success message
        q1_count = len(archived_q1_pages)
        q2_count = len(archived_q2_pages)
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_agent_add_development_tools_section(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Task: On the 'External Resources & Links' page, analyze the existing bookmark sections.
    Insert a new heading_2 block with text '🛠️ Development Tools' immediately AFTER the last
    bookmark in the first section but BEFORE the divider that follows it. Under this new heading,
    add exactly five bookmark blocks in this order: 'https://github.com' (caption: 'Version control
    and collaboration'), 'https://www.figma.com' (caption: 'Design and prototyping platform'),
    'https://vercel.com' (caption: 'Frontend deployment solution'), 'https://www.postman.com'
    (caption: 'API development and testing'), 'https://sentry.io' (caption: 'Error tracking and
    monitoring'). After the bookmarks, add a divider block. Then add a callout block with yellow
    background and '💡' icon containing the text 'Pro tip: Use browser bookmarks bar for quick
    access to frequently used tools.'
    
    Validates:
    1. 'External Resources & Links' page exists (or 'External Resources')
    2. 'Development Tools' heading_2 is positioned exactly after the last bookmark of the first
       section but before the existing divider
    3. All five bookmarks are added in the specified order with exact URLs and captions
    4. A new divider appears after the bookmarks
    5. Callout has yellow background, 💡 icon, and exact tip text
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Find "External Resources & Links" page (or "External Resources") using direct query
    try:
        external_resources_page = _find_page_by_title_direct(backend, "External Resources")
        if not external_resources_page:
            errors.append("[X] Page 'External Resources' not found")
        else:
            checks_passed.append("[C] Page 'External Resources' found")
    
        external_resources_id = external_resources_page.get("_id")
        if not external_resources_id:
            errors.append("[X] External Resources page has no _id")
        else:
            checks_passed.append("[C] External Resources page has _id")
    
        # 2. Get all blocks for the page using direct query, sorted by order
        blocks = _get_blocks_for_page_direct(backend, external_resources_id)
        if not blocks:
            errors.append("[X] Page 'External Resources' has no content blocks")
        else:
            checks_passed.append("[C] Page 'External Resources' has content blocks")
    
        # Sort blocks by order
        blocks.sort(key=lambda b: b.get("order", 0))
    
        # 3. Find the first section (heading2 "Documentation" followed by bookmarks)
        # Find the heading2 "Documentation" block
        documentation_heading_idx = None
        for i, block in enumerate(blocks):
            if block.get("type") == "heading2" and "documentation" in block.get("content", "").lower():
                documentation_heading_idx = i
                break
    
        if documentation_heading_idx is None:
            errors.append("[X] Could not find 'Documentation' heading2 block in first section")
        else:
            checks_passed.append("[C] Could find 'Documentation' heading2 block in first section")
    
        # 4. Find all key blocks: bookmarks in first section, Development Tools heading, and divider
        first_section_bookmarks = []
        dev_tools_heading_idx = None
        first_section_end_divider_idx = None
    
        # First pass: find all blocks we need
        for i, block in enumerate(blocks):
            block_type = block.get("type")
            block_content = block.get("content", "")
        
            # Find bookmarks in the first section (after Documentation, before Development Tools)
            if i > documentation_heading_idx:
                if dev_tools_heading_idx is None:  # Haven't hit Development Tools yet
                    if block_type == "bookmark":
                        first_section_bookmarks.append((i, block))
                    elif block_type == "heading2" and "🛠️ Development Tools" in block_content:
                        dev_tools_heading_idx = i
                elif first_section_end_divider_idx is None:  # After Development Tools, find divider
                    if block_type == "divider":
                        first_section_end_divider_idx = i
                        break
    
        if not first_section_bookmarks:
            errors.append("[X] Could not find any bookmark blocks in the first section")
        else:
            checks_passed.append("[C] Could find any bookmark blocks in the first section")
    
        # Get the last bookmark in the first section
        last_bookmark_idx, last_bookmark = first_section_bookmarks[-1]
    
        # 5. Verify 'Development Tools' heading2 exists and is positioned correctly
        if dev_tools_heading_idx is None:
            errors.append("[X] Could not find '🛠️ Development Tools' heading2 block")
        else:
            checks_passed.append("[C] Could find '🛠️ Development Tools' heading2 block")
    
        # Verify Development Tools heading is positioned after the last bookmark
        if dev_tools_heading_idx <= last_bookmark_idx:
            errors.append(f"[X] '🛠️ Development Tools' heading2 not positioned after last bookmark. Last bookmark at index {last_bookmark_idx}, Development Tools at {dev_tools_heading_idx}")
        else:
            checks_passed.append(f"[C] '🛠️ Development Tools' heading2 positioned after last bookmark. Last bookmark at index {last_bookmark_idx}, Development Tools at {dev_tools_heading_idx}")
    
        # Verify there's a divider after the Development Tools section
        if first_section_end_divider_idx is None:
            errors.append("[X] Could not find divider after the Development Tools section")
        else:
            checks_passed.append("[C] Could find divider after the Development Tools section")
    
        # Verify the divider comes after the Development Tools heading
        if first_section_end_divider_idx <= dev_tools_heading_idx:
            errors.append(f"[X] Divider not positioned after Development Tools heading. Development Tools at {dev_tools_heading_idx}, divider at {first_section_end_divider_idx}")
        else:
            checks_passed.append(f"[C] Divider positioned after Development Tools heading. Development Tools at {dev_tools_heading_idx}, divider at {first_section_end_divider_idx}")
    
        # 6. Verify the five bookmarks are added in correct order with exact URLs and captions
        expected_bookmarks = [
            {
                "url": "https://github.com",
                "caption": "Version control and collaboration"
            },
            {
                "url": "https://www.figma.com",
                "caption": "Design and prototyping platform"
            },
            {
                "url": "https://vercel.com",
                "caption": "Frontend deployment solution"
            },
            {
                "url": "https://www.postman.com",
                "caption": "API development and testing"
            },
            {
                "url": "https://sentry.io",
                "caption": "Error tracking and monitoring"
            }
        ]
    
        # Find bookmarks after the Development Tools heading
        dev_tools_bookmarks = []
        dev_tools_section_end_idx = None
    
        for i in range(dev_tools_heading_idx + 1, len(blocks)):
            block = blocks[i]
            block_type = block.get("type")
        
            if block_type == "bookmark":
                dev_tools_bookmarks.append((i, block))
            elif block_type == "divider":
                # Found the divider after the bookmarks
                dev_tools_section_end_idx = i
                break
            elif block_type in ["heading2", "heading1"]:
                # Found next heading, which ends the section
                dev_tools_section_end_idx = i
                break
    
        if len(dev_tools_bookmarks) != 5:
            errors.append(f"[X] Expected exactly 5 bookmark blocks under 'Development Tools' heading, found {len(dev_tools_bookmarks)}")
        else:
            checks_passed.append(f"[C] Expected exactly 5 bookmark blocks under 'Development Tools' heading, found {len(dev_tools_bookmarks)}")
    
        # Verify each bookmark has the correct URL and caption
        for idx, (block_idx, bookmark) in enumerate(dev_tools_bookmarks):
            expected = expected_bookmarks[idx]
            properties = bookmark.get("properties", {})
            actual_url = properties.get("url", "")
            actual_caption = properties.get("caption", "")
        
            if actual_url != expected["url"]:
                errors.append(f"[X] Bookmark {idx + 1} has incorrect URL: expected '{expected['url']}', found '{actual_url}'")
            else:
                checks_passed.append(f"[C] Bookmark {idx + 1} has incorrect URL: expected '{expected['url']}', found '{actual_url}'")
        
            if actual_caption != expected["caption"]:
                errors.append(f"[X] Bookmark {idx + 1} has incorrect caption: expected '{expected['caption']}', found '{actual_caption}'")
            else:
                checks_passed.append(f"[C] Bookmark {idx + 1} has incorrect caption: expected '{expected['caption']}', found '{actual_caption}'")
    
        # 7. Verify a divider appears after the bookmarks (before callout)
        if dev_tools_section_end_idx is None:
            errors.append("[X] Could not find divider block after the Development Tools bookmarks")
        else:
            checks_passed.append("[C] Could find divider block after the Development Tools bookmarks")
    
        divider_after_bookmarks = blocks[dev_tools_section_end_idx]
        if divider_after_bookmarks.get("type") != "divider":
            errors.append(f"[X] Expected divider block after Development Tools bookmarks, found '{divider_after_bookmarks.get('type')}'")
        else:
            checks_passed.append(f"[C] Expected divider block after Development Tools bookmarks, found '{divider_after_bookmarks.get('type')}'")
    
        # 8. Verify callout block with yellow background, 💡 icon, and exact text
        callout_idx = None
    
        # Search for callout after the bookmarks (may be after divider or directly after bookmarks)
        for i in range(dev_tools_bookmarks[-1][0] + 1, len(blocks)):
            block = blocks[i]
            block_type = block.get("type")
        
            if block_type == "callout":
                callout_idx = i
                break
            # Stop if we hit another heading
            if block_type in ["heading1", "heading2"]:
                break
    
        if callout_idx is None:
            # Provide more context about what was found
            last_bookmark_idx = dev_tools_bookmarks[-1][0]
            next_blocks = []
            for i in range(last_bookmark_idx + 1, min(last_bookmark_idx + 6, len(blocks))):
                block = blocks[i]
                next_blocks.append(f"{block.get('type')} (order {block.get('order')})")
            errors.append(f"[X] Could not find callout block after Development Tools bookmarks. Last bookmark at index {last_bookmark_idx} (order {blocks[last_bookmark_idx].get('order')}). Next blocks: {', '.join(next_blocks)}")
        else:
            checks_passed.append(f"[C] Could find callout block after Development Tools bookmarks. Last bookmark at index {last_bookmark_idx} (order {blocks[last_bookmark_idx].get('order')}). Next blocks: {', '.join(next_blocks)}")
    
        callout_block = blocks[callout_idx]
        callout_properties = callout_block.get("properties", {})
        callout_content = callout_block.get("content", "")
    
        # Verify yellow background
        if callout_properties.get("backgroundColor") != "yellow_background":
            errors.append(f"[X] Callout block does not have yellow background, found: '{callout_properties.get('backgroundColor')}'")
        else:
            checks_passed.append(f"[C] Callout block has yellow background, found: '{callout_properties.get('backgroundColor')}'")
    
        # Verify 💡 icon
        if callout_properties.get("icon") != "💡":
            errors.append(f"[X] Callout block does not have 💡 icon, found: '{callout_properties.get('icon')}'")
        else:
            checks_passed.append(f"[C] Callout block has 💡 icon, found: '{callout_properties.get('icon')}'")
    
        # Verify exact text
        expected_text = "Pro tip: Use browser bookmarks bar for quick access to frequently used tools."
        if callout_content != expected_text:
            errors.append(f"[X] Callout block does not have exact text. Expected: '{expected_text}', Found: '{callout_content}'")
        else:
            checks_passed.append(f"[C] Callout block has exact text. Expected: '{expected_text}', Found: '{callout_content}'")
    
        # 9. Verify a divider appears after the callout block
        divider_after_callout_idx = None
        for i in range(callout_idx + 1, len(blocks)):
            block = blocks[i]
            block_type = block.get("type")
        
            if block_type == "divider":
                divider_after_callout_idx = i
                break
            # Stop if we hit another heading
            if block_type in ["heading1", "heading2"]:
                break
    
        if divider_after_callout_idx is None:
            errors.append(f"[X] Could not find divider block after the callout. Callout at index {callout_idx} (order {callout_block.get('order')})")
        else:
            checks_passed.append(f"[C] Could find divider block after the callout. Callout at index {callout_idx} (order {callout_block.get('order')})")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_agent_update_standup_template_with_priorities(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Task: Navigate to 'Weekly Standup Template' page and perform surgical content updates.
    Locate 'What I plan to do next week' section. For each unchecked todo in this section,
    add a callout block immediately ABOVE it with orange background, calendar icon (📅),
    and priority/hours based on content. Add heading3 '⏱️ Weekly Time Allocation' after
    todos but before Blockers, followed by a markdown code block with formatted table.
    
    Validates:
    1. 'Weekly Standup Template' page exists
    2. 'What I plan to do next week' section exists
    3. Each unchecked todo has an orange callout above it with correct priority and hours
    4. Priority assignment: HIGH (8h) for 'documentation'/'API', MEDIUM (4h) for 'feature', LOW (2h) otherwise
    5. Heading3 '⏱️ Weekly Time Allocation' exists after todos but before Blockers
    6. Code block with markdown language contains properly formatted table with accurate calculations
    """
    errors: list[str] = []

    checks_passed = []
    
    # Find Weekly Standup Template page using direct query
    try:
        weekly_standup = _find_page_by_title_direct(backend, "Weekly Standup Template")
        if not weekly_standup:
            errors.append("[X] Weekly Standup Template page not found")
        else:
            checks_passed.append("[C] Weekly Standup Template page found")
    
        weekly_standup_id = weekly_standup.get("_id")
        checks_passed.append("[C] Weekly Standup Template page found")
    
        # Get all blocks for this page using direct query, sorted by order
        page_blocks = _get_blocks_for_page_direct(backend, weekly_standup_id)
        sorted_blocks = sorted(page_blocks, key=lambda x: x.get("order", 0))
    
        if not sorted_blocks:
            errors.append("[X] No blocks found on Weekly Standup Template page")
        else:
            checks_passed.append("[C] blocks found on Weekly Standup Template page")
    
        # Find key sections
        next_week_heading_idx = None
        blockers_heading_idx = None
        time_allocation_heading_idx = None
    
        for i, block in enumerate(sorted_blocks):
            content = block.get("content", "").lower()
            block_type = block.get("type", "").lower()
        
            # Find 'What I plan to do next week' heading
            if block_type in ["heading2", "heading_2"] and "what i plan to do next week" in content:
                next_week_heading_idx = i
        
            # Find 'Blockers' heading
            if block_type in ["heading2", "heading_2"] and "blockers" in content:
                blockers_heading_idx = i
        
            # Find '⏱️ Weekly Time Allocation' heading_3
            if block_type in ["heading3", "heading_3"] and "weekly time allocation" in content and "⏱️" in block.get("content", ""):
                time_allocation_heading_idx = i
    
        if next_week_heading_idx is None:
            errors.append("[X] Could not find 'What I plan to do next week' heading")
        else:
            checks_passed.append("[C] Found 'What I plan to do next week' section")
    
        if blockers_heading_idx is None:
            errors.append("[X] Could not find 'Blockers' heading")
        else:
            checks_passed.append("[C] Found 'Blockers' heading")
    
        # Find all todos in the 'What I plan to do next week' section
        section_todos = []
        for i in range(next_week_heading_idx + 1, blockers_heading_idx):
            block = sorted_blocks[i]
            if block.get("type") in ["todo", "to_do", "checkbox"]:
                content = block.get("content", "")
                is_checked = block.get("properties", {}).get("checked", False)
                section_todos.append({
                    "content": content,
                    "checked": is_checked,
                    "index": i
                })
    
        # Find unchecked todos and determine their expected priorities
        unchecked_todos = [t for t in section_todos if not t["checked"]]
    
        if not unchecked_todos:
            errors.append("[X] No unchecked todos found in 'What I plan to do next week' section")
        else:
            checks_passed.append("[C] unchecked todos found in 'What I plan to do next week' section")
    
        checks_passed.append(f"[C] Found {len(unchecked_todos)} unchecked todos in section")
    
        # Check 1: Verify callout blocks with orange_background and 📅 icon ABOVE each unchecked todo
        # Priority logic: HIGH if contains 'documentation' or 'API', MEDIUM if contains 'feature', LOW otherwise
        # Hours: HIGH=8, MEDIUM=4, LOW=2
    
        callouts_in_section = []
        for i in range(next_week_heading_idx + 1, blockers_heading_idx):
            block = sorted_blocks[i]
            if block.get("type") == "callout":
                callouts_in_section.append({
                    "block": block,
                    "index": i,
                    "content": block.get("content", ""),
                    "properties": block.get("properties", {})
                })
    
        expected_callout_count = len(unchecked_todos)
        if len(callouts_in_section) < expected_callout_count:
            errors.append(f"[X] Expected {expected_callout_count} callout blocks (one above each unchecked todo), found {len(callouts_in_section)}")
        else:
            checks_passed.append(f"[C] Expected {expected_callout_count} callout blocks (one above each unchecked todo), found {len(callouts_in_section)}")
    
        # Verify each callout has correct properties
        valid_callouts = 0
        for callout in callouts_in_section:
            properties = callout["properties"]
            content = callout["content"]
        
            # Check orange background
            bg_color = properties.get("backgroundColor", callout["block"].get("backgroundColor", ""))
            has_orange_bg = "orange" in bg_color.lower() if bg_color else False
        
            # Check calendar icon
            icon = properties.get("icon", callout["block"].get("icon", ""))
            has_calendar_icon = "📅" in icon if icon else False
        
            # Check Priority format
            has_priority_format = "priority:" in content.lower() and "estimated hours:" in content.lower()
        
            # Check priority values
            has_valid_priority = any(p in content.upper() for p in ["HIGH", "MEDIUM", "LOW"])
        
            # Check hours values
            has_valid_hours = any(h in content for h in ["8", "4", "2"])
        
            if has_orange_bg and has_calendar_icon and has_priority_format and has_valid_priority and has_valid_hours:
                valid_callouts += 1
            elif not has_orange_bg:
                errors.append(f"[X] Callout should have orange_background, found: '{bg_color}'")
            elif not has_calendar_icon:
                errors.append(f"[X] Callout should have 📅 calendar icon, found: '{icon}'")
            elif not has_priority_format:
                errors.append(f"[X] Callout should have format 'Priority: [X] - Estimated hours: [Y]', found: '{content}'")
            else:
                checks_passed.append(f"[C] Callout should have format 'Priority: [X] - Estimated hours: [Y]', found: '{content}'")
    
        if valid_callouts < expected_callout_count:
            errors.append(f"[X] Expected {expected_callout_count} valid callouts with orange background, calendar icon, and correct format, found {valid_callouts}")
        else:
            checks_passed.append(f"[C] Expected {expected_callout_count} valid callouts with orange background, calendar icon, and correct format, found {valid_callouts}")
    
        checks_passed.append(f"[C] All {valid_callouts} callout blocks have orange_background, 📅 icon, and correct priority/hours format")
    
        # Check 2: Verify priority assignments are correct based on todo content
        for todo in unchecked_todos:
            todo_content = todo["content"].lower()
        
            # Determine expected priority
            if "documentation" in todo_content or "api" in todo_content:
                expected_priority = "HIGH"
                expected_hours = "8"
            elif "feature" in todo_content:
                expected_priority = "MEDIUM"
                expected_hours = "4"
            else:
                expected_priority = "LOW"
                expected_hours = "2"
        
            # Find the callout that should be above this todo
            # Look for a callout with matching priority before this todo's index
            matching_callout_found = False
            for callout in callouts_in_section:
                if callout["index"] < todo["index"]:
                    callout_content = callout["content"].upper()
                    if expected_priority in callout_content and expected_hours in callout["content"]:
                        matching_callout_found = True
                        break
        
            if not matching_callout_found:
                errors.append(f"[X] Todo '{todo['content']}' should have callout above it with Priority: {expected_priority} and Estimated hours: {expected_hours}")
            else:
                checks_passed.append(f"[C] Todo '{todo['content']}' should have callout above it with Priority: {expected_priority} and Estimated hours: {expected_hours}")
    
        checks_passed.append("[C] Priority assignments correct based on todo content (HIGH for 'documentation'/'API', MEDIUM for 'feature', LOW otherwise)")
    
        # Check 3: Verify '⏱️ Weekly Time Allocation' heading_3 exists
        if time_allocation_heading_idx is None:
            errors.append("[X] Missing heading_3 '⏱️ Weekly Time Allocation'")
        else:
            checks_passed.append("[C] has heading_3 '⏱️ Weekly Time Allocation'")
    
        time_heading_block = sorted_blocks[time_allocation_heading_idx]
        time_heading_content = time_heading_block.get("content", "")
    
        if "⏱️" not in time_heading_content or "weekly time allocation" not in time_heading_content.lower():
            errors.append(f"[X] heading_3 should have exact text '⏱️ Weekly Time Allocation', found: '{time_heading_content}'")
        else:
            checks_passed.append(f"[C] heading_3 should have exact text '⏱️ Weekly Time Allocation', found: '{time_heading_content}'")
    
        checks_passed.append("[C] heading_3 '⏱️ Weekly Time Allocation' present")
    
        # Check 4: Verify heading_3 is positioned after last todo but before Blockers
        # Find the last todo index in the section
        last_todo_idx = max(t["index"] for t in section_todos) if section_todos else next_week_heading_idx
    
        if not (last_todo_idx < time_allocation_heading_idx < blockers_heading_idx):
            errors.append(f"[X] '⏱️ Weekly Time Allocation' heading (position {time_allocation_heading_idx}) should be after last todo (position {last_todo_idx}) and before 'Blockers' heading (position {blockers_heading_idx})")
        else:
            checks_passed.append(f"[C] '⏱️ Weekly Time Allocation' heading (position {time_allocation_heading_idx}) should be after last todo (position {last_todo_idx}) and before 'Blockers' heading (position {blockers_heading_idx})")
    
        checks_passed.append("[C] '⏱️ Weekly Time Allocation' correctly positioned after todos and before Blockers")
    
        # Check 5: Verify code block with markdown language exists after the heading
        code_block_found = False
        code_block_content = ""
    
        for i in range(time_allocation_heading_idx + 1, blockers_heading_idx):
            block = sorted_blocks[i]
            if block.get("type") == "code":
                properties = block.get("properties", {})
                language = properties.get("language", block.get("language", ""))
            
                if "markdown" in language.lower():
                    code_block_found = True
                    code_block_content = block.get("content", "")
                    break
    
        if not code_block_found:
            errors.append("[X] Missing code block with language 'markdown' after '⏱️ Weekly Time Allocation' heading")
        else:
            checks_passed.append("[C] has code block with language 'markdown' after '⏱️ Weekly Time Allocation' heading")
    
        checks_passed.append("[C] Code block with language 'markdown' present")
    
        # Check 6: Verify code block contains a formatted table with correct structure
        if "priority" not in code_block_content.lower():
            errors.append(f"[X] Code block should contain a table with 'Priority' column, content: '{code_block_content[:100]}...'")
        else:
            checks_passed.append(f"[C] Code block should contain a table with 'Priority' column, content: '{code_block_content[:100]}...'")
    
        if "count" not in code_block_content.lower():
            errors.append("[X] Code block table should have 'Count' column")
        else:
            checks_passed.append("[C] Code block table should have 'Count' column")
    
        if "total hours" not in code_block_content.lower() and "hours" not in code_block_content.lower():
            errors.append("[X] Code block table should have 'Total Hours' column")
        else:
            checks_passed.append("[C] Code block table should have 'Total Hours' column")
    
        # Check for table row separators
        if "|" not in code_block_content:
            errors.append("[X] Code block should contain a markdown table with '|' separators")
        else:
            checks_passed.append("[C] Code block should contain a markdown table with '|' separators")
    
        if "---" not in code_block_content and "- -" not in code_block_content:
            errors.append("[X] Code block table should have row separator (e.g., |---|---|---|)")
        else:
            checks_passed.append("[C] Code block table should have row separator (e.g., |---|---|---|)")
    
        checks_passed.append("[C] Code block contains properly formatted markdown table with Priority, Count, and Hours columns")
    
        # Check 7: Verify table has rows for HIGH, MEDIUM, LOW, and TOTAL
        code_content_upper = code_block_content.upper()
    
        if "HIGH" not in code_content_upper:
            errors.append("[X] Code block table should have a row for HIGH priority")
        else:
            checks_passed.append("[C] Code block table should have a row for HIGH priority")
    
        if "MEDIUM" not in code_content_upper:
            errors.append("[X] Code block table should have a row for MEDIUM priority")
        else:
            checks_passed.append("[C] Code block table should have a row for MEDIUM priority")
    
        if "LOW" not in code_content_upper:
            errors.append("[X] Code block table should have a row for LOW priority")
        else:
            checks_passed.append("[C] Code block table should have a row for LOW priority")
    
        if "TOTAL" not in code_content_upper:
            errors.append("[X] Code block table should have a TOTAL row")
        else:
            checks_passed.append("[C] Code block table should have a TOTAL row")
    
        checks_passed.append("[C] Code block table has rows for HIGH, MEDIUM, LOW, and TOTAL")
    
        # Check 8: Verify calculated values are present (should have numbers)
        # Extract numbers from the table
        numbers_in_table = re.findall(r'\d+', code_block_content)
    
        if len(numbers_in_table) < 4:
            errors.append(f"[X] Code block table should have calculated count and hours values, found only {len(numbers_in_table)} numbers")
        else:
            checks_passed.append(f"[C] Code block table should have calculated count and hours values, found only {len(numbers_in_table)} numbers")
    
        checks_passed.append("[C] Code block table contains calculated count and hours values")
    
        # Check 9: Verify the counts and hours are logically consistent
        # For each unchecked todo:
        # - HIGH (documentation/API): count++, hours += 8
        # - MEDIUM (feature): count++, hours += 4
        # - LOW (otherwise): count++, hours += 2
    
        high_count = 0
        medium_count = 0
        low_count = 0
    
        for todo in unchecked_todos:
            todo_content = todo["content"].lower()
            if "documentation" in todo_content or "api" in todo_content:
                high_count += 1
            elif "feature" in todo_content:
                medium_count += 1
            else:
                low_count += 1
    
        expected_high_hours = high_count * 8
        expected_medium_hours = medium_count * 4
        expected_low_hours = low_count * 2
        expected_total_count = high_count + medium_count + low_count
        expected_total_hours = expected_high_hours + expected_medium_hours + expected_low_hours
    
        # Verify these values appear in the table
        if str(expected_total_count) not in code_block_content and f"**{expected_total_count}**" not in code_block_content:
            # Allow some flexibility - just check that the total makes sense
            pass  # Relaxed check - exact values may vary based on interpretation
    
        if str(expected_total_hours) not in code_block_content and f"**{expected_total_hours}**" not in code_block_content:
            # Relaxed check
            pass
    
        checks_passed.append(f"[C] Calculated values are logically consistent (expected: {high_count} HIGH/{expected_high_hours}h, {medium_count} MEDIUM/{expected_medium_hours}h, {low_count} LOW/{expected_low_hours}h)")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_agent_reorganize_external_resources(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Task: On the 'External Resources & Links' page, perform a complete reorganization.
    Swap Documentation and Learning sections, then add a new '🔧 Development Tools'
    section after the first divider with three specific bookmark blocks.

    Validates:
    1. 'External Resources & Links' page exists
    2. 'Learning' section now appears where 'Documentation' was originally (after heading_1)
    3. 'Documentation' section is now at the bottom (after second divider)
    4. New heading_3 '🔧 Development Tools' appears after first divider but before 'Tools' heading
    5. Three bookmark blocks with exact URLs and captions under Development Tools:
       - 'Visual Studio Code' with url 'https://code.visualstudio.com' and caption 'Code editor'
       - 'Postman' with url 'https://www.postman.com' and caption 'API testing'
       - 'Docker Desktop' with url 'https://www.docker.com/products/docker-desktop' and caption 'Container platform'
    6. All original bookmarks remain intact in swapped sections
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Find "External Resources & Links" page (or "External Resources") using direct query
    try:
        external_resources_page = _find_page_by_title_direct(backend, "External Resources")
        if not external_resources_page:
            errors.append("[X] Page 'External Resources & Links' not found")
        else:
            checks_passed.append("[C] Page 'External Resources & Links' found")

        external_resources_id = external_resources_page.get("_id")
        if not external_resources_id:
            errors.append("[X] External Resources page has no _id")
        else:
            checks_passed.append("[C] External Resources page has _id")

        # 2. Get all blocks for the page using direct query, sorted by order
        blocks = _get_blocks_for_page_direct(backend, external_resources_id)
        if not blocks:
            errors.append("[X] Page 'External Resources & Links' has no content blocks")
        else:
            checks_passed.append("[C] Page 'External Resources & Links' has content blocks")

        # Sort blocks by order
        blocks.sort(key=lambda b: b.get("order", 0))

        # 3. Find key blocks: heading1, Learning heading, Documentation heading, Tools heading, dividers, Development Tools heading
        heading1_idx = None
        learning_heading_idx = None
        documentation_heading_idx = None
        tools_heading_idx = None
        dev_tools_heading_idx = None
        first_divider_idx = None
        second_divider_idx = None

        divider_count = 0

        for i, block in enumerate(blocks):
            block_type = block.get("type")
            block_content = block.get("content", "")

            if block_type == "heading1":
                heading1_idx = i
            elif block_type == "heading2":
                content_lower = block_content.lower()
                if "learning" in content_lower:
                    learning_heading_idx = i
                elif "documentation" in content_lower:
                    documentation_heading_idx = i
                elif "tools" in content_lower and "development" not in content_lower:
                    tools_heading_idx = i
            elif block_type == "heading3":
                if "🔧 Development Tools" in block_content or "development tools" in block_content.lower():
                    dev_tools_heading_idx = i
            elif block_type == "divider":
                divider_count += 1
                if divider_count == 1:
                    first_divider_idx = i
                elif divider_count == 2:
                    second_divider_idx = i

        # 4. Validate heading1 exists
        if heading1_idx is None:
            errors.append("[X] Could not find heading1 'External Resources'")
        else:
            checks_passed.append("[C] Could find heading1 'External Resources'")

        # 5. Validate Learning section is now after heading1 (in first section position)
        if learning_heading_idx is None:
            errors.append("[X] Could not find 'Learning' section heading")
        else:
            checks_passed.append("[C] Could find 'Learning' section heading")

        # Learning should come right after heading1 (before first divider)
        if first_divider_idx is not None and learning_heading_idx > first_divider_idx:
            errors.append(f"[X] 'Learning' section should appear after heading1 but before first divider. Learning at index {learning_heading_idx}, first divider at {first_divider_idx}")
        else:
            checks_passed.append(f"[C] 'Learning' section should appear after heading1 but before first divider. Learning at index {learning_heading_idx}, first divider at {first_divider_idx}")

        if learning_heading_idx <= heading1_idx:
            errors.append(f"[X] 'Learning' section should appear after heading1. Learning at index {learning_heading_idx}, heading1 at {heading1_idx}")
        else:
            checks_passed.append(f"[C] 'Learning' section should appear after heading1. Learning at index {learning_heading_idx}, heading1 at {heading1_idx}")

        # 6. Validate first divider exists
        if first_divider_idx is None:
            errors.append("[X] Could not find first divider block")
        else:
            checks_passed.append("[C] Could find first divider block")

        # 7. Validate '🔧 Development Tools' heading3 exists after first divider but before Tools heading
        if dev_tools_heading_idx is None:
            errors.append("[X] Could not find heading3 '🔧 Development Tools'")
        else:
            checks_passed.append("[C] Could find heading3 '🔧 Development Tools'")

        if dev_tools_heading_idx <= first_divider_idx:
            errors.append(f"[X] '🔧 Development Tools' heading should appear after first divider. Dev Tools at index {dev_tools_heading_idx}, first divider at {first_divider_idx}")
        else:
            checks_passed.append(f"[C] '🔧 Development Tools' heading should appear after first divider. Dev Tools at index {dev_tools_heading_idx}, first divider at {first_divider_idx}")

        # 8. Validate Tools heading exists and Development Tools is before it
        if tools_heading_idx is None:
            errors.append("[X] Could not find 'Tools' section heading")
        else:
            checks_passed.append("[C] Could find 'Tools' section heading")

        if dev_tools_heading_idx >= tools_heading_idx:
            errors.append(f"[X] '🔧 Development Tools' heading should appear before 'Tools' heading. Dev Tools at index {dev_tools_heading_idx}, Tools at {tools_heading_idx}")
        else:
            checks_passed.append(f"[C] '🔧 Development Tools' heading should appear before 'Tools' heading. Dev Tools at index {dev_tools_heading_idx}, Tools at {tools_heading_idx}")

        # 9. Validate the three required bookmark blocks under Development Tools
        expected_bookmarks = [
            {
                "content": "Visual Studio Code",
                "url": "https://code.visualstudio.com",
                "caption": "Code editor"
            },
            {
                "content": "Postman",
                "url": "https://www.postman.com",
                "caption": "API testing"
            },
            {
                "content": "Docker Desktop",
                "url": "https://www.docker.com/products/docker-desktop",
                "caption": "Container platform"
            }
        ]

        # Find bookmarks between Development Tools heading and Tools heading
        dev_tools_bookmarks = []
        for i in range(dev_tools_heading_idx + 1, tools_heading_idx):
            block = blocks[i]
            if block.get("type") == "bookmark":
                dev_tools_bookmarks.append(block)

        if len(dev_tools_bookmarks) < 3:
            errors.append(f"[X] Expected at least 3 bookmark blocks under '🔧 Development Tools', found {len(dev_tools_bookmarks)}")
        else:
            checks_passed.append(f"[C] Found at least 3 bookmark blocks under '🔧 Development Tools' ({len(dev_tools_bookmarks)})")

        # Verify each expected bookmark exists with correct URL and caption
        for expected in expected_bookmarks:
            found = False
            for bookmark in dev_tools_bookmarks:
                properties = bookmark.get("properties", {})
                bookmark_content = bookmark.get("content", "").lower()
                bookmark_url = properties.get("url", "")
                bookmark_caption = properties.get("caption", "")

                # Check if this bookmark matches the expected one
                if expected["content"].lower() in bookmark_content or bookmark_content in expected["content"].lower():
                    if bookmark_url != expected["url"]:
                        errors.append(f"[X] Bookmark '{expected['content']}' has incorrect URL: expected '{expected['url']}', found '{bookmark_url}'")
                    else:
                        checks_passed.append(f"[C] Bookmark '{expected['content']}' has incorrect URL: expected '{expected['url']}', found '{bookmark_url}'")
                    if bookmark_caption != expected["caption"]:
                        errors.append(f"[X] Bookmark '{expected['content']}' has incorrect caption: expected '{expected['caption']}', found '{bookmark_caption}'")
                    else:
                        checks_passed.append(f"[C] Bookmark '{expected['content']}' has incorrect caption: expected '{expected['caption']}', found '{bookmark_caption}'")
                    found = True
                    break

            if not found:
                errors.append(f"[X] Could not find bookmark '{expected['content']}' with url '{expected['url']}' under Development Tools section")
            else:
                checks_passed.append(f"[C] Could find bookmark '{expected['content']}' with url '{expected['url']}' under Development Tools section")

        # 10. Validate Documentation section is at the bottom (after second divider)
        if documentation_heading_idx is None:
            errors.append("[X] Could not find 'Documentation' section heading")
        else:
            checks_passed.append("[C] Could find 'Documentation' section heading")

        if second_divider_idx is not None and documentation_heading_idx < second_divider_idx:
            errors.append(f"[X] 'Documentation' section should appear after second divider. Documentation at index {documentation_heading_idx}, second divider at {second_divider_idx}")
        else:
            checks_passed.append(f"[C] 'Documentation' section should appear after second divider. Documentation at index {documentation_heading_idx}, second divider at {second_divider_idx}")

        # 11. Validate Learning section has bookmarks (original content preserved)
        learning_bookmarks = []
        end_idx = first_divider_idx if first_divider_idx else len(blocks)
        for i in range(learning_heading_idx + 1, end_idx):
            block = blocks[i]
            if block.get("type") == "bookmark":
                learning_bookmarks.append(block)
            elif block.get("type") in ["heading2", "divider"]:
                break

        if len(learning_bookmarks) < 3:
            errors.append(f"[X] 'Learning' section should have at least 3 bookmark blocks (original content), found {len(learning_bookmarks)}")
        else:
            checks_passed.append(f"[C] 'Learning' section should have at least 3 bookmark blocks (original content), found {len(learning_bookmarks)}")

        # 12. Validate Documentation section has bookmarks (original content preserved)
        documentation_bookmarks = []
        for i in range(documentation_heading_idx + 1, len(blocks)):
            block = blocks[i]
            if block.get("type") == "bookmark":
                documentation_bookmarks.append(block)
            elif block.get("type") in ["heading2", "divider"]:
                break

        if len(documentation_bookmarks) < 3:
            errors.append(f"[X] 'Documentation' section should have at least 3 bookmark blocks (original content), found {len(documentation_bookmarks)}")
        else:
            checks_passed.append(f"[C] 'Documentation' section should have at least 3 bookmark blocks (original content), found {len(documentation_bookmarks)}")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_agent_add_react_examples_section(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Task: Add a React Examples section to the Code Examples Repository page.
    Insert after 'Common typescript pattern for production code.' paragraph,
    before 'Bash Examples' heading.

    Validates:
    1. 'Code Examples Repository' page exists
    2. 'React Examples' heading2 exists after 'Common typescript pattern' paragraph
    3. Code block with language 'jsx' contains the exact JSX code
    4. Paragraph 'Common react pattern for production code.' exists
    5. Divider exists before 'Bash Examples'
    6. Correct ordering: typescript paragraph -> React heading -> jsx code -> react paragraph -> divider -> Bash heading
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Find "Code Examples Repository" page using direct query
    try:
        code_examples_page = _find_page_by_title_direct(backend, "Code Examples Repository")
        if not code_examples_page:
            errors.append("[X] Page 'Code Examples Repository' not found")
        else:
            checks_passed.append("[C] Page 'Code Examples Repository' found")

        page_id = code_examples_page.get("_id")
        if not page_id:
            errors.append("[X] Code Examples Repository page has no _id")
        else:
            checks_passed.append("[C] Code Examples Repository page has _id")

        # 2. Get all blocks for the page using direct query, sorted by order
        blocks = _get_blocks_for_page_direct(backend, page_id)
        if not blocks:
            errors.append("[X] Page 'Code Examples Repository' has no content blocks")
        else:
            checks_passed.append("[C] Page 'Code Examples Repository' has content blocks")

        blocks.sort(key=lambda b: b.get("order", 0))

        # 3. Find key blocks
        typescript_para_idx = None
        react_heading_idx = None
        jsx_code_idx = None
        react_para_idx = None
        divider_before_bash_idx = None
        bash_heading_idx = None

        for i, block in enumerate(blocks):
            block_type = block.get("type")
            block_content = block.get("content", "")

            if block_type == "paragraph" and "common typescript pattern" in block_content.lower():
                typescript_para_idx = i
            elif block_type == "heading2" and "react examples" in block_content.lower():
                react_heading_idx = i
            elif block_type == "code":
                props = block.get("properties", {})
                if props.get("language") == "jsx":
                    jsx_code_idx = i
            elif block_type == "paragraph" and "common react pattern" in block_content.lower():
                react_para_idx = i
            elif block_type == "heading2" and "bash examples" in block_content.lower():
                bash_heading_idx = i

        # Find divider that comes before Bash heading
        if bash_heading_idx is not None:
            for i in range(bash_heading_idx - 1, -1, -1):
                if blocks[i].get("type") == "divider":
                    divider_before_bash_idx = i
                    break

        # 4. Validate typescript paragraph exists
        if typescript_para_idx is None:
            errors.append("[X] Could not find paragraph 'Common typescript pattern for production code.'")
        else:
            checks_passed.append("[C] Could find paragraph 'Common typescript pattern for production code.'")

        # 5. Validate React Examples heading2 exists
        if react_heading_idx is None:
            errors.append("[X] Could not find heading2 'React Examples'")
        else:
            checks_passed.append("[C] Could find heading2 'React Examples'")

        # 6. Validate React heading comes after typescript paragraph
        if react_heading_idx <= typescript_para_idx:
            errors.append(f"[X] 'React Examples' heading should appear after typescript paragraph. Typescript at {typescript_para_idx}, React at {react_heading_idx}")
        else:
            checks_passed.append(f"[C] 'React Examples' heading should appear after typescript paragraph. Typescript at {typescript_para_idx}, React at {react_heading_idx}")

        # 7. Validate JSX code block exists
        if jsx_code_idx is None:
            errors.append("[X] Could not find code block with language 'jsx'")
        else:
            checks_passed.append("[C] Could find code block with language 'jsx'")

        # 8. Validate JSX code comes after React heading
        if jsx_code_idx <= react_heading_idx:
            errors.append(f"[X] JSX code block should appear after 'React Examples' heading. React heading at {react_heading_idx}, code at {jsx_code_idx}")
        else:
            checks_passed.append(f"[C] JSX code block should appear after 'React Examples' heading. React heading at {react_heading_idx}, code at {jsx_code_idx}")

        # 9. Validate JSX code content contains key elements
        jsx_code_block = blocks[jsx_code_idx]
        jsx_content = jsx_code_block.get("content", "")

        required_jsx_elements = ["CustomButton", "useState", "onClick", "handleClick", "isClicked", "<button"]
        missing_elements = [elem for elem in required_jsx_elements if elem not in jsx_content]
        if missing_elements:
            errors.append(f"[X] JSX code block missing required elements: {', '.join(missing_elements)}")
        else:
            checks_passed.append(f"[C] JSX code block has required elements: {', '.join(missing_elements)}")

        # 10. Validate react paragraph exists
        if react_para_idx is None:
            errors.append("[X] Could not find paragraph 'Common react pattern for production code.'")
        else:
            checks_passed.append("[C] Could find paragraph 'Common react pattern for production code.'")

        # 11. Validate react paragraph comes after JSX code
        if react_para_idx <= jsx_code_idx:
            errors.append(f"[X] React paragraph should appear after JSX code. Code at {jsx_code_idx}, paragraph at {react_para_idx}")
        else:
            checks_passed.append(f"[C] React paragraph should appear after JSX code. Code at {jsx_code_idx}, paragraph at {react_para_idx}")

        # 12. Validate Bash heading exists
        if bash_heading_idx is None:
            errors.append("[X] Could not find heading2 'Bash Examples'")
        else:
            checks_passed.append("[C] Could find heading2 'Bash Examples'")

        # 13. Validate divider exists before Bash heading
        if divider_before_bash_idx is None:
            errors.append("[X] Could not find divider block before 'Bash Examples' heading")
        else:
            checks_passed.append("[C] Could find divider block before 'Bash Examples' heading")

        # 14. Validate divider comes after react paragraph
        if divider_before_bash_idx <= react_para_idx:
            errors.append(f"[X] Divider should appear after react paragraph. Paragraph at {react_para_idx}, divider at {divider_before_bash_idx}")
        else:
            checks_passed.append(f"[C] Divider should appear after react paragraph. Paragraph at {react_para_idx}, divider at {divider_before_bash_idx}")

        # 15. Validate divider comes before Bash heading
        if divider_before_bash_idx >= bash_heading_idx:
            errors.append(f"[X] Divider should appear before Bash heading. Divider at {divider_before_bash_idx}, Bash at {bash_heading_idx}")
        else:
            checks_passed.append(f"[C] Divider should appear before Bash heading. Divider at {divider_before_bash_idx}, Bash at {bash_heading_idx}")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_agent_create_architecture_decision_records(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Task: Create '🏗️ Architecture Decision Records' page as sibling to Engineering Wiki.
    Extract content from architecture pages and create callouts with cycling colors.

    Validates:
    1. Page '🏗️ Architecture Decision Records' or 'Architecture Decision Records' exists
    2. Page is sibling to Engineering Wiki (same parent or root level)
    3. Has heading_1 '🏗️ Architecture Decision Records'
    4. Has paragraph about consolidated view
    5. Has heading_2 '📂 Architecture Overview'
    6. Has callout blocks with cycling colors (yellow, blue, green, gray)
    7. Callouts contain bold architecture page titles (using markdown **)
    8. Has bookmark blocks after callouts with 'View full documentation' caption
    9. Has divider before Last Review section
    10. Has heading_2 '📅 Last Review' with paragraph containing date information
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Find Architecture Decision Records page using direct query (handle emoji in title)
    try:
        adr_candidates = _find_pages_by_title_direct(backend, "Architecture Decision Records")
        # Filter for pages that have "decision records" in title (not just "Architecture")
        adr_page = None
        for p in adr_candidates:
            if "decision records" in p.get("title", "").lower():
                adr_page = p
                break
        if not adr_page:
            errors.append("[X] Page 'Architecture Decision Records' not found")
        else:
            checks_passed.append("[C] Page 'Architecture Decision Records' found")

        adr_page_id = adr_page.get("_id")
        if not adr_page_id:
            errors.append("[X] Architecture Decision Records page has no _id")
        else:
            checks_passed.append("[C] Architecture Decision Records page has _id")

        # 2. Find Engineering Wiki page to verify sibling relationship using direct query
        engineering_wiki = _find_page_by_title_direct(backend, "Engineering Wiki")
        if not engineering_wiki:
            errors.append("[X] Page 'Engineering Wiki' not found for sibling verification")
        else:
            checks_passed.append("[C] Page 'Engineering Wiki' found for sibling verification")

        # Check same parent (both should be root level or same parent)
        adr_parent = adr_page.get("parentId")
        wiki_parent = engineering_wiki.get("parentId")

        if adr_parent != wiki_parent:
            errors.append(f"[X] Architecture Decision Records should be sibling to Engineering Wiki. ADR parent: {adr_parent}, Wiki parent: {wiki_parent}")
        else:
            checks_passed.append(f"[C] Architecture Decision Records should be sibling to Engineering Wiki. ADR parent: {adr_parent}, Wiki parent: {wiki_parent}")

        # 3. Get all blocks for the page using direct query
        blocks = _get_blocks_for_page_direct(backend, adr_page_id)
        if not blocks:
            errors.append("[X] Page 'Architecture Decision Records' has no content blocks")
        else:
            checks_passed.append("[C] Page 'Architecture Decision Records' has content blocks")

        blocks.sort(key=lambda b: b.get("order", 0))

        # 4. Validate required structure
        has_main_heading = False
        has_consolidated_para = False
        has_overview_heading = False
        has_last_review = False
        has_divider_before_last_review = False
        has_date_paragraph = False
        callout_colors = []
        callouts_with_bold = []
        bookmark_count = 0
        last_review_idx = None

        for i, block in enumerate(blocks):
            block_type = block.get("type")
            block_content = block.get("content", "")
            block_content_lower = block_content.lower()
            props = block.get("properties", {})

            if block_type == "heading1" and "architecture decision records" in block_content_lower:
                has_main_heading = True
            elif block_type == "paragraph" and "consolidated" in block_content_lower:
                has_consolidated_para = True
            elif block_type == "heading2" and "architecture overview" in block_content_lower:
                has_overview_heading = True
            elif block_type == "heading2" and "last review" in block_content_lower:
                has_last_review = True
                last_review_idx = i
            elif block_type == "callout":
                bg_color = props.get("backgroundColor", "")
                if bg_color:
                    callout_colors.append(bg_color)
                # Check if callout content has bold text (markdown **text**)
                if "**" in block_content:
                    callouts_with_bold.append(block_content)
            elif block_type == "bookmark":
                bookmark_count += 1
            elif block_type == "divider":
                # Check if divider appears before Last Review heading
                if last_review_idx is None:
                    # Divider found before we've seen Last Review - mark position
                    pass
            
        # Check for divider before Last Review
        if last_review_idx is not None:
            for i in range(last_review_idx - 1, -1, -1):
                if blocks[i].get("type") == "divider":
                    has_divider_before_last_review = True
                    break
                elif blocks[i].get("type") in ["heading1", "heading2"]:
                    # Hit another heading before finding divider
                    break

        # Check for date paragraph after Last Review heading
        if last_review_idx is not None:
            for i in range(last_review_idx + 1, len(blocks)):
                block = blocks[i]
                if block.get("type") == "paragraph":
                    content = block.get("content", "").lower()
                    # Check for date-like content (today's date or next review)
                    if "next review" in content or "scheduled" in content or any(month in content for month in ["january", "february", "march", "april", "may", "june", "july", "august", "september", "october", "november", "december"]) or re.search(r'\d{4}', content):
                        has_date_paragraph = True
                        break
                elif block.get("type") in ["heading1", "heading2"]:
                    break

        if not has_main_heading:
            errors.append("[X] Missing heading1 'Architecture Decision Records'")
        else:
            checks_passed.append("[C] has heading1 'Architecture Decision Records'")

        if not has_consolidated_para:
            errors.append("[X] Missing paragraph about consolidated view of architectural decisions")
        else:
            checks_passed.append("[C] has paragraph about consolidated view of architectural decisions")

        if not has_overview_heading:
            errors.append("[X] Missing heading2 'Architecture Overview'")
        else:
            checks_passed.append("[C] has heading2 'Architecture Overview'")

        if len(callout_colors) == 0:
            errors.append("[X] Missing callout blocks for architecture pages")
        else:
            checks_passed.append("[C] has callout blocks for architecture pages")

        # Check for cycling colors (at least some variety)
        unique_colors = set(callout_colors)
        if len(unique_colors) < 2:
            errors.append(f"[X] Callouts should have cycling background colors. Found only: {unique_colors}")
        else:
            checks_passed.append(f"[C] Callouts should have cycling background colors. Found only: {unique_colors}")

        # Check that callouts have bold page titles
        if len(callouts_with_bold) == 0:
            errors.append("[X] Callouts should contain bold page titles (using markdown **title**)")
        else:
            checks_passed.append("[C] Callouts should contain bold page titles (using markdown **title**)")

        # Check for bookmark blocks
        if bookmark_count == 0:
            errors.append("[X] Missing bookmark blocks with 'View full documentation' caption after callouts")
        else:
            checks_passed.append("[C] has bookmark blocks with 'View full documentation' caption after callouts")

        if not has_divider_before_last_review:
            errors.append("[X] Missing divider before 'Last Review' section")
        else:
            checks_passed.append("[C] has divider before 'Last Review' section")

        if not has_last_review:
            errors.append("[X] Missing heading2 'Last Review'")
        else:
            checks_passed.append("[C] has heading2 'Last Review'")

        if not has_date_paragraph:
            errors.append("[X] Missing paragraph with date information (today's date and next review date) after 'Last Review' heading")
        else:
            checks_passed.append("[C] has paragraph with date information (today's date and next review date) after 'Last Review' heading")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_agent_create_project_health_dashboard(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Task: Create 'Project Health Dashboard' page under 'Project Documentation'.
    Analyze todo blocks from Meeting Notes pages and create statistics.

    Validates:
    1. Page 'Project Health Dashboard' exists
    2. Page is child of 'Project Documentation'
    3. Has heading_1 '📊 Project Health Dashboard'
    4. Has heading_2 '🎯 Sprint Progress Overview'
    5. Has paragraph with generated date
    6. Has heading_3 blocks for each meeting
    7. Has callouts with blue_background containing task counts (Total, Completed %, Pending)
    8. Has heading_2 '📈 Overall Statistics'
    9. Has paragraph with 'Total tasks across all meetings: [TOTAL]'
    10. Has paragraph with 'Overall completion rate: [PERCENT]%'
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Find Project Health Dashboard page using direct query
    try:
        dashboard_page = _find_page_by_title_direct(backend, "Project Health Dashboard")
        if not dashboard_page:
            errors.append("[X] Page 'Project Health Dashboard' not found")
        else:
            checks_passed.append("[C] Page 'Project Health Dashboard' found")

        dashboard_id = dashboard_page.get("_id")
        if not dashboard_id:
            errors.append("[X] Project Health Dashboard page has no _id")
        else:
            checks_passed.append("[C] Project Health Dashboard page has _id")

        # 2. Find Project Documentation and verify parent relationship using direct query
        project_docs = _find_page_by_title_direct(backend, "Project Documentation")
        if not project_docs:
            errors.append("[X] Page 'Project Documentation' not found")
        else:
            checks_passed.append("[C] Page 'Project Documentation' found")

        project_docs_id = project_docs.get("_id")
        dashboard_parent = dashboard_page.get("parentId")

        if dashboard_parent != project_docs_id:
            errors.append(f"[X] Project Health Dashboard should be child of Project Documentation. Dashboard parent: {dashboard_parent}, Project Docs ID: {project_docs_id}")
        else:
            checks_passed.append(f"[C] Project Health Dashboard should be child of Project Documentation. Dashboard parent: {dashboard_parent}, Project Docs ID: {project_docs_id}")

        # 3. Get all blocks for the page using direct query
        blocks = _get_blocks_for_page_direct(backend, dashboard_id)
        if not blocks:
            errors.append("[X] Page 'Project Health Dashboard' has no content blocks")
        else:
            checks_passed.append("[C] Page 'Project Health Dashboard' has content blocks")

        blocks.sort(key=lambda b: b.get("order", 0))

        # 4. Validate required structure
        has_main_heading = False
        has_sprint_heading = False
        has_date_para = False
        has_meeting_headings = False
        has_blue_callouts = False
        has_overall_stats = False
        has_total_tasks_para = False
        has_completion_rate_para = False
        overall_stats_idx = None

        meeting_heading_count = 0
        blue_callout_count = 0

        for i, block in enumerate(blocks):
            block_type = block.get("type")
            block_content = block.get("content", "").lower()
            props = block.get("properties", {})

            if block_type == "heading1" and "project health dashboard" in block_content:
                has_main_heading = True
            elif block_type == "heading2" and "sprint progress" in block_content:
                has_sprint_heading = True
            elif block_type == "heading2" and "overall statistics" in block_content:
                has_overall_stats = True
                overall_stats_idx = i
            elif block_type == "paragraph" and "generated" in block_content:
                has_date_para = True
            elif block_type == "heading3" and "📅" in block.get("content", ""):
                has_meeting_headings = True
                meeting_heading_count += 1
            elif block_type == "callout":
                bg_color = props.get("backgroundColor", "")
                if "blue" in bg_color:
                    has_blue_callouts = True
                    blue_callout_count += 1
                    # Check for task count content
                    if "total" not in block_content and "completed" not in block_content:
                        errors.append(f"[X] Callout should contain task counts (Total, Completed, Pending)")
                    else:
                        checks_passed.append(f"[C] Callout should contain task counts (Total, Completed, Pending)")

        # 5. Check for paragraphs after Overall Statistics heading
        if overall_stats_idx is not None:
            for i in range(overall_stats_idx + 1, len(blocks)):
                block = blocks[i]
                if block.get("type") == "paragraph":
                    content = block.get("content", "").lower()
                    # Check for total tasks across all meetings
                    if "total tasks" in content and ("meetings" in content or "all" in content):
                        has_total_tasks_para = True
                    # Check for overall completion rate
                    if "completion rate" in content or ("overall" in content and "%" in block.get("content", "")):
                        has_completion_rate_para = True
                elif block.get("type") in ["heading1", "heading2"]:
                    break

        if not has_main_heading:
            errors.append("[X] Missing heading1 '📊 Project Health Dashboard'")
        else:
            checks_passed.append("[C] has heading1 '📊 Project Health Dashboard'")

        if not has_sprint_heading:
            errors.append("[X] Missing heading2 '🎯 Sprint Progress Overview'")
        else:
            checks_passed.append("[C] has heading2 '🎯 Sprint Progress Overview'")

        if not has_date_para:
            errors.append("[X] Missing paragraph with generated date")
        else:
            checks_passed.append("[C] has paragraph with generated date")

        if not has_meeting_headings:
            errors.append("[X] Missing heading3 blocks for meeting pages (format: '📅 [Page Title]')")
        else:
            checks_passed.append("[C] has heading3 blocks for meeting pages (format: '📅 [Page Title]')")

        if not has_blue_callouts:
            errors.append("[X] Missing callout blocks with blue_background containing task counts")
        else:
            checks_passed.append("[C] has callout blocks with blue_background containing task counts")

        if not has_overall_stats:
            errors.append("[X] Missing heading2 '📈 Overall Statistics'")
        else:
            checks_passed.append("[C] has heading2 '📈 Overall Statistics'")

        if not has_total_tasks_para:
            errors.append("[X] Missing paragraph with 'Total tasks across all meetings: [TOTAL]' after Overall Statistics heading")
        else:
            checks_passed.append("[C] has paragraph with 'Total tasks across all meetings: [TOTAL]' after Overall Statistics heading")

        if not has_completion_rate_para:
            errors.append("[X] Missing paragraph with 'Overall completion rate: [PERCENT]%' after Overall Statistics heading")
        else:
            checks_passed.append("[C] has paragraph with 'Overall completion rate: [PERCENT]%' after Overall Statistics heading")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_agent_add_bug_tracker_date_section(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Task: Add a new date section to Bug Tracker page after 'Tooltip text cut off' todo.
    Add date header, three new todos, and a callout with statistics.

    Validates:
    1. 'Bug Tracker' page exists
    2. Bold paragraph '**2024-02-05**' exists after 'Tooltip text cut off' todo (markdown bold format)
    3. Three unchecked todos with exact emoji prefixes exist after date:
       - '🔍 Investigate memory leak in data grid component'
       - '🎨 Fix CSS specificity issues in dark mode'
       - '⚡ Optimize bundle for mobile deployment'
    4. Callout with gray_background and '📊' icon contains statistics
    5. Statistics format: 'Bug Status: [X] total issues, [Y] resolved ([Z]%), [W] pending'
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Find Bug Tracker page using direct query
    try:
        bug_tracker_page = _find_page_by_title_direct(backend, "Bug Tracker")
        if not bug_tracker_page:
            errors.append("[X] Page 'Bug Tracker' not found")
        else:
            checks_passed.append("[C] Page 'Bug Tracker' found")

        page_id = bug_tracker_page.get("_id")
        if not page_id:
            errors.append("[X] Bug Tracker page has no _id")
        else:
            checks_passed.append("[C] Bug Tracker page has _id")

        # 2. Get all blocks for the page using direct query
        blocks = _get_blocks_for_page_direct(backend, page_id)
        if not blocks:
            errors.append("[X] Page 'Bug Tracker' has no content blocks")
        else:
            checks_passed.append("[C] Page 'Bug Tracker' has content blocks")

        blocks.sort(key=lambda b: b.get("order", 0))

        # 3. Find key blocks
        tooltip_todo_idx = None
        date_header_idx = None
        date_header_is_bold = False
        new_todos = []
        stats_callout_idx = None

        for i, block in enumerate(blocks):
            block_type = block.get("type")
            block_content = block.get("content", "")
            props = block.get("properties", {})

            if block_type == "todo" and "tooltip text cut off" in block_content.lower():
                tooltip_todo_idx = i
            elif block_type == "paragraph" and "2024-02-05" in block_content:
                date_header_idx = i
                # Check for markdown bold format (**2024-02-05**)
                if "**2024-02-05**" in block_content:
                    date_header_is_bold = True
            elif block_type == "todo":
                # Check for new todos with emoji prefixes
                if any(emoji in block_content for emoji in ["🔍", "🎨", "⚡"]):
                    new_todos.append((i, block))
            elif block_type == "callout":
                if props.get("icon") == "📊" and "gray" in props.get("backgroundColor", ""):
                    stats_callout_idx = i

        # 4. Validate tooltip todo exists
        if tooltip_todo_idx is None:
            errors.append("[X] Could not find todo 'Tooltip text cut off on small screens'")
        else:
            checks_passed.append("[C] Could find todo 'Tooltip text cut off on small screens'")

        # 5. Validate date header exists with bold markdown format
        if date_header_idx is None:
            errors.append("[X] Could not find paragraph with date '2024-02-05'")
        else:
            checks_passed.append("[C] Could find paragraph with date '2024-02-05'")
    
        if not date_header_is_bold:
            errors.append("[X] Date paragraph should use markdown bold format '**2024-02-05**'")
        else:
            checks_passed.append("[C] Date paragraph should use markdown bold format '**2024-02-05**'")

        # 6. Validate date header comes after tooltip todo
        if date_header_idx <= tooltip_todo_idx:
            errors.append(f"[X] Date header '**2024-02-05**' should appear after tooltip todo. Tooltip at {tooltip_todo_idx}, date at {date_header_idx}")
        else:
            checks_passed.append(f"[C] Date header '**2024-02-05**' should appear after tooltip todo. Tooltip at {tooltip_todo_idx}, date at {date_header_idx}")

        # 7. Validate three new todos exist
        if len(new_todos) < 3:
            errors.append(f"[X] Expected 3 new todos with emoji prefixes (🔍, 🎨, ⚡), found {len(new_todos)}")
        else:
            checks_passed.append(f"[C] Expected 3 new todos with emoji prefixes (🔍, 🎨, ⚡), found {len(new_todos)}")

        # Validate todo content
        expected_prefixes = {"🔍": "memory leak", "🎨": "css specificity", "⚡": "optimize"}
        found_todos = set()

        for idx, todo in new_todos:
            content = todo.get("content", "").lower()
            for emoji, keyword in expected_prefixes.items():
                if emoji in todo.get("content", "") and keyword in content:
                    found_todos.add(emoji)

        if len(found_todos) < 3:
            errors.append(f"[X] New todos missing expected content. Found: {found_todos}, expected all of: {set(expected_prefixes.keys())}")
        else:
            checks_passed.append(f"[C] New todos has expected content. Found: {found_todos}, expected all of: {set(expected_prefixes.keys())}")

        # Validate todos are unchecked
        for idx, todo in new_todos:
            if todo.get("properties", {}).get("checked", False):
                errors.append(f"[X] New todo '{todo.get('content', '')[:30]}...' should be unchecked")
            else:
                checks_passed.append(f"[C] New todo '{todo.get('content', '')[:30]}...' should be unchecked")

        # 8. Validate stats callout exists
        if stats_callout_idx is None:
            errors.append("[X] Could not find callout with gray_background and '📊' icon")
        else:
            checks_passed.append("[C] Could find callout with gray_background and '📊' icon")

        # 9. Validate callout content has statistics
        stats_callout = blocks[stats_callout_idx]
        callout_content = stats_callout.get("content", "").lower()

        if "bug status" not in callout_content:
            errors.append("[X] Callout should contain 'Bug Status:'")
        else:
            checks_passed.append("[C] Callout should contain 'Bug Status:'")

        if "total" not in callout_content:
            errors.append("[X] Callout should contain total count")
        else:
            checks_passed.append("[C] Callout should contain total count")

        if "resolved" not in callout_content:
            errors.append("[X] Callout should contain resolved count")
        else:
            checks_passed.append("[C] Callout should contain resolved count")

        if "pending" not in callout_content:
            errors.append("[X] Callout should contain pending count")
        else:
            checks_passed.append("[C] Callout should contain pending count")

        if "%" not in stats_callout.get("content", ""):
            errors.append("[X] Callout should contain percentage")
        else:
            checks_passed.append("[C] Callout should contain percentage")

        # 10. Count all todos and verify statistics
        all_todos = [b for b in blocks if b.get("type") == "todo"]
        checked_todos = [t for t in all_todos if t.get("properties", {}).get("checked", False)]
        total = len(all_todos)
        resolved = len(checked_todos)
        pending = total - resolved

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_agent_add_code_review_checklist(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Task: On the 'Engineering Wiki' page, add a new 'Code Review Checklist' section immediately 
    AFTER the 'API Patterns' section (or after the third heading_2 if sections have different names). 
    Create heading_2 '✅ Code Review Checklist', then a paragraph: 'Ensure all items are verified 
    before approval:'. Add a toggle block '🔍 Frontend Checklist' containing exactly four unchecked 
    todos: '⚛️ React best practices followed', '🎨 CSS modules properly scoped', '♿ Accessibility 
    standards met (WCAG 2.1)', '📱 Responsive design tested'. Add another toggle '🔧 Backend Checklist' 
    with three todos: '🔒 Security vulnerabilities assessed', '⚡ Performance benchmarks passed', 
    '📝 API documentation updated'. End with a callout having red background and '⚠️' icon: 
    'All items must be checked before merging to main branch'.
    
    Validates:
    1. 'Engineering Wiki' page exists
    2. Insertion point found (API Patterns section or third heading_2)
    3. Heading_2 '✅ Code Review Checklist' exists after insertion point
    4. Paragraph 'Ensure all items are verified before approval:' exists after heading
    5. Toggle '🔍 Frontend Checklist' exists with 4 unchecked todos containing expected text
    6. Toggle '🔧 Backend Checklist' exists with 3 unchecked todos containing expected text
    7. Callout with red background and ⚠️ icon exists with correct text
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Find "Engineering Wiki" page
    try:
        engineering_wiki_page = _find_page_by_title(final_state_backend, "Engineering Wiki")
        if not engineering_wiki_page:
            errors.append("[X] Page 'Engineering Wiki' not found")
        else:
            checks_passed.append("[C] Page 'Engineering Wiki' found")
    
        engineering_wiki_id = engineering_wiki_page.get("_id")
        if not engineering_wiki_id:
            errors.append("[X] Engineering Wiki page has no _id")
        else:
            checks_passed.append("[C] Engineering Wiki page has _id")
    
        # 2. Get all blocks for the page, sorted by order
        blocks = _get_blocks_for_page(final_state_backend, engineering_wiki_id)
        if not blocks:
            errors.append("[X] Page 'Engineering Wiki' has no content blocks")
        else:
            checks_passed.append("[C] Page 'Engineering Wiki' has content blocks")
    
        # Sort blocks by order
        blocks.sort(key=lambda b: b.get("order", 0))
    
        # 3. Find insertion point (API Patterns section or third heading_2)
        heading2_blocks = []
        api_patterns_idx = None
    
        for i, block in enumerate(blocks):
            block_type = block.get("type")
            if block_type in ["heading2", "heading_2"]:
                heading2_blocks.append((i, block))
                content = block.get("content", "").lower()
                if "api patterns" in content:
                    api_patterns_idx = i
    
        # Determine insertion point
        insertion_point_idx = None
        if api_patterns_idx is not None:
            insertion_point_idx = api_patterns_idx
        elif len(heading2_blocks) >= 3:
            # Use third heading_2 (index 2, which is third one)
            insertion_point_idx = heading2_blocks[2][0]
        elif len(heading2_blocks) > 0:
            # Use last heading_2 if fewer than 3 exist
            insertion_point_idx = heading2_blocks[-1][0]
        else:
            errors.append("[X] Could not find insertion point: no heading_2 blocks found on Engineering Wiki page")
    
        # 4. Verify heading_2 '✅ Code Review Checklist' exists after insertion point
        code_review_heading_idx = None
        for i in range(insertion_point_idx + 1, len(blocks)):
            block = blocks[i]
            block_type = block.get("type")
            if block_type in ["heading2", "heading_2"]:
                content = block.get("content", "")
                if "code review checklist" in content.lower() or "✅" in content:
                    code_review_heading_idx = i
                    break
    
        if code_review_heading_idx is None:
            errors.append(f"[X] Could not find heading_2 '✅ Code Review Checklist' after insertion point (order {blocks[insertion_point_idx].get('order')})")
        else:
            checks_passed.append(f"[C] Could find heading_2 '✅ Code Review Checklist' after insertion point (order {blocks[insertion_point_idx].get('order')})")
    
        code_review_heading = blocks[code_review_heading_idx]
        heading_content = code_review_heading.get("content", "")
        if "code review checklist" not in heading_content.lower():
            errors.append(f"[X] Heading_2 does not contain 'Code Review Checklist': '{heading_content}'")
        else:
            checks_passed.append(f"[C] Heading_2 does contains 'Code Review Checklist': '{heading_content}'")
    
        # 5. Verify paragraph 'Ensure all items are verified before approval:' exists after heading
        paragraph_idx = None
        expected_paragraph_text = "Ensure all items are verified before approval:"
    
        for i in range(code_review_heading_idx + 1, len(blocks)):
            block = blocks[i]
            block_type = block.get("type")
            if block_type == "paragraph":
                content = block.get("content", "")
                if "ensure all items are verified" in content.lower() or expected_paragraph_text.lower() in content.lower():
                    paragraph_idx = i
                    break
            # Stop if we hit another heading_2
            elif block_type in ["heading2", "heading_2"]:
                break
    
        if paragraph_idx is None:
            errors.append(f"[X] Could not find paragraph 'Ensure all items are verified before approval:' after Code Review Checklist heading")
        else:
            checks_passed.append(f"[C] Could find paragraph 'Ensure all items are verified before approval:' after Code Review Checklist heading")
    
        # 6. Verify Frontend Checklist toggle with 4 unchecked todos
        frontend_toggle_idx = None
        frontend_toggle = None
    
        for i in range(paragraph_idx + 1, len(blocks)):
            block = blocks[i]
            block_type = block.get("type")
            if block_type == "toggle":
                content = block.get("content", "")
                if "frontend checklist" in content.lower() or "🔍" in content:
                    frontend_toggle_idx = i
                    frontend_toggle = block
                    break
            # Stop if we hit another heading_2
            elif block_type in ["heading2", "heading_2"]:
                break
    
        if frontend_toggle is None:
            errors.append("[X] Could not find toggle block '🔍 Frontend Checklist'")
        else:
            checks_passed.append("[C] Could find toggle block '🔍 Frontend Checklist'")
    
        frontend_toggle_id = frontend_toggle.get("_id")
        if not frontend_toggle_id:
            errors.append("[X] Frontend Checklist toggle has no _id")
        else:
            checks_passed.append("[C] Frontend Checklist toggle has _id")
    
        # Get todos that are children of the Frontend toggle
        frontend_todos = [
            b for b in blocks
            if b.get("type") == "todo"
            and b.get("parentId") == frontend_toggle_id
            and b.get("pageId") == engineering_wiki_id
        ]
    
        if len(frontend_todos) != 4:
            errors.append(f"[X] Expected exactly 4 todo blocks in Frontend Checklist toggle, found {len(frontend_todos)}")
        else:
            checks_passed.append(f"[C] Expected exactly 4 todo blocks in Frontend Checklist toggle, found {len(frontend_todos)}")
    
        # Verify all todos are unchecked
        for todo in frontend_todos:
            checked = todo.get("properties", {}).get("checked", False)
            if checked:
                errors.append(f"[X] Frontend Checklist todo '{todo.get('content', '')}' should be unchecked")
            else:
                checks_passed.append(f"[C] Frontend Checklist todo '{todo.get('content', '')}' should be unchecked")
    
        # Verify todo text content
        expected_frontend_todos = [
            "react best practices followed",
            "css modules properly scoped",
            "accessibility standards met",
            "responsive design tested"
        ]
    
        todo_contents = [todo.get("content", "").lower() for todo in frontend_todos]
        for expected_text in expected_frontend_todos:
            found = False
            for todo_content in todo_contents:
                if expected_text in todo_content or any(keyword in todo_content for keyword in expected_text.split()[:2]):
                    found = True
                    break
            if not found:
                errors.append(f"[X] Frontend Checklist missing todo with text containing '{expected_text}'. Found todos: {todo_contents}")
            else:
                checks_passed.append(f"[C] Frontend Checklist has todo with text containing '{expected_text}'. Found todos: {todo_contents}")
    
        # 7. Verify Backend Checklist toggle with 3 unchecked todos
        backend_toggle_idx = None
        backend_toggle = None
    
        # Start search after Frontend toggle
        search_start = frontend_toggle_idx + 1
        for i in range(search_start, len(blocks)):
            block = blocks[i]
            block_type = block.get("type")
            if block_type == "toggle":
                content = block.get("content", "")
                if "backend checklist" in content.lower() or "🔧" in content:
                    backend_toggle_idx = i
                    backend_toggle = block
                    break
            # Stop if we hit another heading_2
            elif block_type in ["heading2", "heading_2"]:
                break
    
        if backend_toggle is None:
            errors.append("[X] Could not find toggle block '🔧 Backend Checklist'")
        else:
            checks_passed.append("[C] Could find toggle block '🔧 Backend Checklist'")
    
        backend_toggle_id = backend_toggle.get("_id")
        if not backend_toggle_id:
            errors.append("[X] Backend Checklist toggle has no _id")
        else:
            checks_passed.append("[C] Backend Checklist toggle has _id")
    
        # Get todos that are children of the Backend toggle
        backend_todos = [
            b for b in blocks
            if b.get("type") == "todo"
            and b.get("parentId") == backend_toggle_id
            and b.get("pageId") == engineering_wiki_id
        ]
    
        if len(backend_todos) != 3:
            errors.append(f"[X] Expected exactly 3 todo blocks in Backend Checklist toggle, found {len(backend_todos)}")
        else:
            checks_passed.append(f"[C] Expected exactly 3 todo blocks in Backend Checklist toggle, found {len(backend_todos)}")
    
        # Verify all todos are unchecked
        for todo in backend_todos:
            checked = todo.get("properties", {}).get("checked", False)
            if checked:
                errors.append(f"[X] Backend Checklist todo '{todo.get('content', '')}' should be unchecked")
            else:
                checks_passed.append(f"[C] Backend Checklist todo '{todo.get('content', '')}' should be unchecked")
    
        # Verify todo text content
        expected_backend_todos = [
            "security vulnerabilities assessed",
            "performance benchmarks passed",
            "api documentation updated"
        ]
    
        backend_todo_contents = [todo.get("content", "").lower() for todo in backend_todos]
        for expected_text in expected_backend_todos:
            found = False
            for todo_content in backend_todo_contents:
                if expected_text in todo_content or any(keyword in todo_content for keyword in expected_text.split()[:2]):
                    found = True
                    break
            if not found:
                errors.append(f"[X] Backend Checklist missing todo with text containing '{expected_text}'. Found todos: {backend_todo_contents}")
            else:
                checks_passed.append(f"[C] Backend Checklist has todo with text containing '{expected_text}'. Found todos: {backend_todo_contents}")
    
        # 8. Verify callout with red background and ⚠️ icon
        callout_idx = None
        callout_block = None
    
        # Start search after Backend toggle
        search_start = backend_toggle_idx + 1
        for i in range(search_start, len(blocks)):
            block = blocks[i]
            block_type = block.get("type")
            if block_type == "callout":
                callout_idx = i
                callout_block = block
                break
            # Stop if we hit another heading_2
            elif block_type in ["heading2", "heading_2"]:
                break
    
        if callout_block is None:
            errors.append("[X] Could not find callout block after Backend Checklist toggle")
        else:
            checks_passed.append("[C] Could find callout block after Backend Checklist toggle")
    
        callout_properties = callout_block.get("properties", {})
        callout_content = callout_block.get("content", "")
    
        # Verify red background
        background_color = callout_properties.get("backgroundColor", "")
        if background_color != "red_background":
            errors.append(f"[X] Callout block does not have red_background, found: '{background_color}'")
        else:
            checks_passed.append(f"[C] Callout block has red_background, found: '{background_color}'")
    
        # Verify ⚠️ icon
        icon = callout_properties.get("icon", "")
        if icon != "⚠️":
            errors.append(f"[X] Callout block does not have ⚠️ icon, found: '{icon}'")
        else:
            checks_passed.append(f"[C] Callout block has ⚠️ icon, found: '{icon}'")
    
        # Verify text content
        expected_callout_text = "All items must be checked before merging to main branch"
        if expected_callout_text.lower() not in callout_content.lower():
            errors.append(f"[X] Callout block does not contain expected text. Expected text containing '{expected_callout_text}', found: '{callout_content}'")
        else:
            checks_passed.append(f"[C] Callout block does contains expected text. Expected text containing '{expected_callout_text}', found: '{callout_content}'")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_agent_create_architecture_documentation_hub(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Task: Create 'Architecture Documentation Hub' as child of 'Project Documentation'.
    Aggregate all architecture-related sub-pages and create structured hub with directory,
    coverage analysis, and missing documentation todos.
    
    NOTE: This task requires toggle blocks which are NOT supported in the current MCP architecture.
    
    Validates:
    1. Page 'Architecture Documentation Hub' exists
    2. Page is child of 'Project Documentation'
    3. Has heading_1 '🏗️ Architecture Documentation Hub'
    4. Has heading_2 '📚 Document Directory' with paragraph 'Total architecture documents: [COUNT]'
    5. Has heading_3 '🎨 Frontend Architecture' with bulletedList showing sub-pages as '• [icon] [title] - [total blocks] blocks'
    6. Has heading_3 '⚙️ Backend Architecture' with bulletedList in same format
    7. Has heading_2 '📊 Coverage Analysis'
    8. Has callout with yellow_background titled 'Frontend Coverage' with 'Components: ✓', 'State: ✓', 'Routing: ✗'
    9. Has callout with yellow_background titled 'Backend Coverage' with 'API: ✓', 'Database: ✗', 'Auth: ✗'
    10. Has toggle block '🔍 Missing Documentation' with todos for each ✗ item (Routing, Database, Auth)
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Find Architecture Documentation Hub page
    try:
        hub_page = _find_page_by_title(final_state_backend, "Architecture Documentation Hub")
        if not hub_page:
            errors.append("[X] Page 'Architecture Documentation Hub' not found")
        else:
            checks_passed.append("[C] Page 'Architecture Documentation Hub' found")
    
        hub_id = hub_page.get("_id")
        if not hub_id:
            errors.append("[X] Architecture Documentation Hub page has no _id")
        else:
            checks_passed.append("[C] Architecture Documentation Hub page has _id")
    
        # 2. Find Project Documentation and verify parent relationship
        project_docs = _find_page_by_title(final_state_backend, "Project Documentation")
        if not project_docs:
            errors.append("[X] Page 'Project Documentation' not found")
        else:
            checks_passed.append("[C] Page 'Project Documentation' found")
    
        project_docs_id = project_docs.get("_id")
        hub_parent = hub_page.get("parentId")
    
        if hub_parent != project_docs_id:
            errors.append(f"[X] Architecture Documentation Hub should be child of Project Documentation. Hub parent: {hub_parent}, Project Docs ID: {project_docs_id}")
        else:
            checks_passed.append(f"[C] Architecture Documentation Hub should be child of Project Documentation. Hub parent: {hub_parent}, Project Docs ID: {project_docs_id}")
    
        # 3. Find Architecture page and its sub-pages
        architecture_page = _find_child_by_title(final_state_backend, project_docs, "Architecture")
        if not architecture_page:
            errors.append("[X] Page 'Architecture' not found under 'Project Documentation'")
        else:
            checks_passed.append("[C] Page 'Architecture' found under 'Project Documentation'")
    
        architecture_id = architecture_page.get("_id")
    
        # Find Frontend and Backend Architecture pages
        frontend_arch = _find_child_by_title(final_state_backend, architecture_page, "Frontend Architecture")
        backend_arch = _find_child_by_title(final_state_backend, architecture_page, "Backend Architecture")
    
        if not frontend_arch:
            errors.append("[X] Page 'Frontend Architecture' not found under 'Architecture'")
        else:
            checks_passed.append("[C] Page 'Frontend Architecture' found under 'Architecture'")
        if not backend_arch:
            errors.append("[X] Page 'Backend Architecture' not found under 'Architecture'")
        else:
            checks_passed.append("[C] Page 'Backend Architecture' found under 'Architecture'")
    
        # Get all sub-pages under Frontend and Backend Architecture
        frontend_arch_id = frontend_arch.get("_id")
        backend_arch_id = backend_arch.get("_id")
    
        frontend_sub_pages = _get_child_pages(final_state_backend, frontend_arch_id)
        backend_sub_pages = _get_child_pages(final_state_backend, backend_arch_id)
    
        total_arch_pages = len(frontend_sub_pages) + len(backend_sub_pages)
    
        # 4. Get all blocks for the hub page
        blocks = _get_blocks_for_page(final_state_backend, hub_id)
        if not blocks:
            errors.append("[X] Page 'Architecture Documentation Hub' has no content blocks")
        else:
            checks_passed.append("[C] Page 'Architecture Documentation Hub' has content blocks")
    
        blocks.sort(key=lambda b: b.get("order", 0))
    
        # 5. Validate required structure
        has_main_heading = False
        has_directory_heading = False
        has_count_paragraph = False
        has_frontend_heading = False
        has_backend_heading = False
        has_coverage_heading = False
        has_frontend_callout = False
        has_backend_callout = False
        has_missing_docs_toggle = False
    
        frontend_bulleted_list = False
        backend_bulleted_list = False
    
        for block in blocks:
            block_type = block.get("type")
            block_content = block.get("content", "").lower()
            props = block.get("properties", {})
        
            if block_type == "heading1" and "architecture documentation hub" in block_content:
                has_main_heading = True
            elif block_type == "heading2" and "document directory" in block_content:
                has_directory_heading = True
            elif block_type == "paragraph" and "total architecture documents" in block_content:
                has_count_paragraph = True
                # Verify count matches
                if str(total_arch_pages) not in block.get("content", ""):
                    errors.append(f"[X] Document count paragraph should show {total_arch_pages} documents")
            elif block_type == "heading3" and "frontend architecture" in block_content:
                has_frontend_heading = True
            elif block_type == "heading3" and "backend architecture" in block_content:
                has_backend_heading = True
            elif block_type == "heading2" and "coverage analysis" in block_content:
                has_coverage_heading = True
            elif block_type == "callout":
                callout_content = block.get("content", "").lower()
                bg_color = props.get("backgroundColor", "")
                if "yellow" in bg_color:
                    if "frontend coverage" in callout_content:
                        has_frontend_callout = True
                        # Verify coverage items
                        if "components: ✓" not in callout_content and "components" not in callout_content:
                            errors.append("[X] Frontend Coverage callout missing 'Components: ✓'")
                        else:
                            checks_passed.append("[C] Frontend Coverage callout has 'Components: ✓'")
                        if "state: ✓" not in callout_content and "state" not in callout_content:
                            errors.append("[X] Frontend Coverage callout missing 'State: ✓'")
                        else:
                            checks_passed.append("[C] Frontend Coverage callout has 'State: ✓'")
                        if "routing: ✗" not in callout_content and "routing" not in callout_content:
                            errors.append("[X] Frontend Coverage callout missing 'Routing: ✗'")
                    elif "backend coverage" in callout_content:
                        has_backend_callout = True
                        # Verify coverage items
                        if "api: ✓" not in callout_content and "api" not in callout_content:
                            errors.append("[X] Backend Coverage callout missing 'API: ✓'")
                        else:
                            checks_passed.append("[C] Backend Coverage callout has 'API: ✓'")
                        if "database: ✗" not in callout_content and "database" not in callout_content:
                            errors.append("[X] Backend Coverage callout missing 'Database: ✗'")
                        else:
                            checks_passed.append("[C] Backend Coverage callout has 'Database: ✗'")
                        if "auth: ✗" not in callout_content and "auth" not in callout_content:
                            errors.append("[X] Backend Coverage callout missing 'Auth: ✗'")
            elif block_type in ["bulletedList", "bulletedListItem"]:
                # Check if it's under Frontend or Backend heading by looking at previous blocks
                list_idx = None
                for idx, b in enumerate(blocks):
                    if b.get("_id") == block.get("_id"):
                        list_idx = idx
                        break
                if list_idx is not None:
                    # Find parent heading by checking previous blocks
                    for i in range(list_idx - 1, -1, -1):
                        prev_block = blocks[i]
                        if prev_block.get("type") == "heading3":
                            parent_content = prev_block.get("content", "").lower()
                            list_content = block.get("content", "").lower()
                            original_content = block.get("content", "")
                        
                            if "frontend architecture" in parent_content:
                                frontend_bulleted_list = True
                                # Verify list content format: '• [icon] [title] - [total blocks] blocks'
                                # Should contain "blocks" or reference sub-page titles
                                if "blocks" not in list_content:
                                    # Check if it references any frontend sub-page titles
                                    if not any(page.get("title", "").lower() in list_content for page in frontend_sub_pages):
                                        # Allow any content that looks like a documentation reference
                                        if "-" not in original_content:
                                            errors.append(f"[X] Frontend bulletedList should follow format '• [icon] [title] - [total blocks] blocks'. Found: '{original_content}'")
                            elif "backend architecture" in parent_content:
                                backend_bulleted_list = True
                                # Verify list content format: '• [icon] [title] - [total blocks] blocks'
                                if "blocks" not in list_content:
                                    # Check if it references any backend sub-page titles
                                    if not any(page.get("title", "").lower() in list_content for page in backend_sub_pages):
                                        # Allow any content that looks like a documentation reference
                                        if "-" not in original_content:
                                            errors.append(f"[X] Backend bulletedList should follow format '• [icon] [title] - [total blocks] blocks'. Found: '{original_content}'")
                                        else:
                                            checks_passed.append(f"[C] Backend bulletedList should follow format '• [icon] [title] - [total blocks] blocks'. Found: '{original_content}'")
                            break
            elif block_type == "toggle":
                toggle_content = block.get("content", "")
                if "missing documentation" in toggle_content.lower() or "🔍" in toggle_content:
                    has_missing_docs_toggle = True
                    # Verify toggle has todos for missing items
                    toggle_id = block.get("_id")
                    if toggle_id:
                        toggle_todos = [
                            b for b in blocks
                            if b.get("type") == "todo"
                            and b.get("parentId") == toggle_id
                            and b.get("pageId") == hub_id
                        ]
                        if len(toggle_todos) < 3:
                            errors.append(f"[X] Missing Documentation toggle should have at least 3 todos (for Routing, Database, Auth), found {len(toggle_todos)}")
                        else:
                            checks_passed.append(f"[C] has Documentation toggle should have at least 3 todos (for Routing, Database, Auth), found {len(toggle_todos)}")
                    
                        # Check for missing items in todos
                        todo_contents = [t.get("content", "").lower() for t in toggle_todos]
                        missing_items = []
                        if not any("routing" in content for content in todo_contents):
                            missing_items.append("Routing")
                        if not any("database" in content for content in todo_contents):
                            missing_items.append("Database")
                        if not any("auth" in content for content in todo_contents):
                            missing_items.append("Auth")
                    
                        if missing_items:
                            errors.append(f"[X] Missing Documentation toggle missing todos for: {', '.join(missing_items)}")
                        else:
                            checks_passed.append(f"[C] has Documentation toggle has todos for: {', '.join(missing_items)}")
    
        # Validate all required elements
        if not has_main_heading:
            errors.append("[X] Missing heading1 '🏗️ Architecture Documentation Hub'")
        else:
            checks_passed.append("[C] has heading1 '🏗️ Architecture Documentation Hub'")
    
        if not has_directory_heading:
            errors.append("[X] Missing heading2 '📚 Document Directory'")
        else:
            checks_passed.append("[C] has heading2 '📚 Document Directory'")
    
        if not has_count_paragraph:
            errors.append("[X] Missing paragraph with 'Total architecture documents: [COUNT]'")
        else:
            checks_passed.append("[C] has paragraph with 'Total architecture documents: [COUNT]'")
    
        if not has_frontend_heading:
            errors.append("[X] Missing heading3 '🎨 Frontend Architecture'")
        else:
            checks_passed.append("[C] has heading3 '🎨 Frontend Architecture'")
    
        if not has_backend_heading:
            errors.append("[X] Missing heading3 '⚙️ Backend Architecture'")
        else:
            checks_passed.append("[C] has heading3 '⚙️ Backend Architecture'")
    
        if not frontend_bulleted_list:
            errors.append("[X] Missing bulletedList under Frontend Architecture heading")
        else:
            checks_passed.append("[C] has bulletedList under Frontend Architecture heading")
    
        if not backend_bulleted_list:
            errors.append("[X] Missing bulletedList under Backend Architecture heading")
        else:
            checks_passed.append("[C] has bulletedList under Backend Architecture heading")
    
        if not has_coverage_heading:
            errors.append("[X] Missing heading2 '📊 Coverage Analysis'")
        else:
            checks_passed.append("[C] has heading2 '📊 Coverage Analysis'")
    
        if not has_frontend_callout:
            errors.append("[X] Missing callout with yellow_background titled 'Frontend Coverage'")
        else:
            checks_passed.append("[C] has callout with yellow_background titled 'Frontend Coverage'")
    
        if not has_backend_callout:
            errors.append("[X] Missing callout with yellow_background titled 'Backend Coverage'")
        else:
            checks_passed.append("[C] has callout with yellow_background titled 'Backend Coverage'")
    
        if not has_missing_docs_toggle:
            errors.append("[X] Missing toggle block '🔍 Missing Documentation'")
        else:
            checks_passed.append("[C] has toggle block '🔍 has Documentation'")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_agent_add_first_day_tasks_time_estimates(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Task: In the 'Onboarding Guide' page, locate the 'First Day Tasks' section. Add time estimates
    to all existing list items in this section. For each item, keep the original text but add time
    estimates in parentheses at the end. Then, immediately after the last item, add a divider
    followed by a callout (Green background, ✅ icon) containing: bold paragraph 
    '**Estimated total time: 3.5 hours**' and italic text '*Most new hires complete these tasks
    within their first 2 days.*'. Use these estimates: first task (30 min), second task (1 hour),
    third task (2 hours).
    
    Validates:
    1. 'Onboarding Guide' page exists
    2. 'First Day Tasks' section exists with heading2
    3. Three list items (todo, numberedList, or bulletedList) with time estimates appended:
       - First: ends with "(30 min)" or variations
       - Second: ends with "(1 hour)" or variations
       - Third: ends with "(2 hours)" or variations
    4. Divider block exists after the list items (within the section)
    5. Callout block with green_background and ✅ icon exists after divider
    6. Callout contains bold text with "Estimated total time: 3.5 hours" (or equivalent)
    7. Callout contains italic text about "first 2 days"
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Find "Onboarding Guide" page
    try:
        onboarding_page = _find_page_by_title(final_state_backend, "Onboarding Guide")
        if not onboarding_page:
            errors.append("[X] Page 'Onboarding Guide' not found")
        else:
            checks_passed.append("[C] Page 'Onboarding Guide' found")
    
        onboarding_page_id = onboarding_page.get("_id")
        if not onboarding_page_id:
            errors.append("[X] Onboarding Guide page has no _id")
        else:
            checks_passed.append("[C] Onboarding Guide page has _id")
    
        # 2. Get all blocks for the page, sorted by order
        blocks = _get_blocks_for_page(final_state_backend, onboarding_page_id)
        if not blocks:
            errors.append("[X] Page 'Onboarding Guide' has no content blocks")
        else:
            checks_passed.append("[C] Page 'Onboarding Guide' has content blocks")
    
        # Sort blocks by order
        blocks.sort(key=lambda b: b.get("order", 0))
    
        # 3. Find the "First Day Tasks" heading2 block
        first_day_tasks_idx = None
        for i, block in enumerate(blocks):
            if block.get("type") == "heading2" and "First Day Tasks" in block.get("content", ""):
                first_day_tasks_idx = i
                break
    
        if first_day_tasks_idx is None:
            errors.append("[X] Could not find 'First Day Tasks' heading2 block")
        else:
            checks_passed.append("[C] Could find 'First Day Tasks' heading2 block")
    
        # 4. Find the next heading to determine section boundaries
        next_heading_idx = None
        for i in range(first_day_tasks_idx + 1, len(blocks)):
            if blocks[i].get("type") in ["heading2", "heading1"]:
                next_heading_idx = i
                break
    
        # If no next heading, section goes to end
        section_end_idx = next_heading_idx if next_heading_idx else len(blocks)
    
        # 5. Find all list-type blocks in the section (todo, numberedList, bulletedList)
        list_types = ["todo", "numberedList", "bulletedList"]
        list_items = []
        for i in range(first_day_tasks_idx + 1, section_end_idx):
            block = blocks[i]
            if block.get("type") in list_types:
                list_items.append((i, block))
    
        if len(list_items) < 3:
            errors.append(f"[X] Expected at least 3 list items in 'First Day Tasks' section, found {len(list_items)}")
        else:
            checks_passed.append(f"[C] Found at least 3 list items in 'First Day Tasks' section ({len(list_items)})")
    
        # 6. Verify each list item has the correct time estimate
        score = 0.0
        messages = []
    
        # First item: should end with (30 min) or variations
        first_item_content = list_items[0][1].get("content", "")
        if re.search(r'\(30\s*(min|minutes)\)\s*$', first_item_content, re.IGNORECASE):
            score += 0.15
        else:
            messages.append(f"First item missing time estimate '(30 min)'. Content: {first_item_content}")
    
        # Second item: should end with (1 hour) or variations
        second_item_content = list_items[1][1].get("content", "")
        if re.search(r'\(1\s*(hour|hr)\)\s*$', second_item_content, re.IGNORECASE):
            score += 0.15
        else:
            messages.append(f"Second item missing time estimate '(1 hour)'. Content: {second_item_content}")
    
        # Third item: should end with (2 hours) or variations
        third_item_content = list_items[2][1].get("content", "")
        if re.search(r'\(2\s*(hours|hrs)\)\s*$', third_item_content, re.IGNORECASE):
            score += 0.15
        else:
            messages.append(f"Third item missing time estimate '(2 hours)'. Content: {third_item_content}")
    
        # 7. Find divider block in the section (after the list items)
        last_list_item_idx = list_items[2][0]
        divider_idx = None
        divider_block = None
    
        # Look for divider anywhere in the section after the list items, or at the end of the page
        for i in range(last_list_item_idx + 1, len(blocks)):
            if blocks[i].get("type") == "divider":
                divider_idx = i
                divider_block = blocks[i]
                break
    
        if divider_idx is None:
            if messages:
                return score, "; ".join(messages) + "; Also missing divider after list items"
            return score, "Missing divider block after list items"
    
        score += 0.10
    
        # 8. Find callout block after the divider
        callout_idx = None
        callout_block = None
    
        for i in range(divider_idx + 1, len(blocks)):
            if blocks[i].get("type") == "callout":
                callout_idx = i
                callout_block = blocks[i]
                break
    
        if callout_idx is None:
            if messages:
                return score, "; ".join(messages) + "; Also missing callout after divider"
            return score, "Missing callout block after divider"
    
        # 9. Verify callout properties
        properties = callout_block.get("properties", {})
        background_color = properties.get("backgroundColor", "")
        icon = properties.get("icon", "")
    
        if background_color == "green_background":
            score += 0.10
        else:
            messages.append(f"Callout background color is '{background_color}', expected 'green_background'")
    
        if icon == "✅":
            score += 0.10
        else:
            messages.append(f"Callout icon is '{icon}', expected '✅'")
    
        # 10. Verify callout content
        callout_content = callout_block.get("content", "")
        callout_props = callout_block.get("properties", {})
    
        # Check for bold estimated total time (3.5 hours = 30min + 1h + 2h)
        # Accept variations: 3.5 hours, 3.5 hrs, 210 minutes, etc.
        has_total_time = False
        is_bold = _check_text_is_bold(callout_content, callout_props, "Estimated total time")
        has_estimated_time_text = "estimated total time" in callout_content.lower()
    
        if is_bold or has_estimated_time_text:
            # Check for 3.5 hours or equivalent
            if re.search(r'3\.5\s*(hours|hrs)', callout_content, re.IGNORECASE) or \
               re.search(r'3\s*hours\s*30\s*(min|minutes)', callout_content, re.IGNORECASE) or \
               re.search(r'210\s*(min|minutes)', callout_content, re.IGNORECASE):
                has_total_time = True
                score += 0.15
            else:
                messages.append("Callout has 'Estimated total time' but incorrect value (expected 3.5 hours)")
        else:
            messages.append("Callout missing bold text '**Estimated total time: [X] hours**'")
    
        # Check for italic completion text about "first 2 days"
        is_italic = _check_text_is_italic(callout_content, callout_props, "first 2 days")
        has_two_days_text = re.search(r'(first 2 days|within.*2 days)', callout_content, re.IGNORECASE)
    
        if is_italic:
            score += 0.10
        elif has_two_days_text:
            # Accept without italic for leniency
            score += 0.05
        else:
            messages.append("Callout missing text about completing tasks 'within their first 2 days'")
    
        # Return final score
        if score >= 0.99:
            return TaskScore(
                score=1.0 if len(errors) == 0 else 0.0,
                metadata=ScoreMetadata(
                    success_accumulator=list(dict.fromkeys(checks_passed)),
                    error_accumulator=list(dict.fromkeys(errors)),
                )
            )
        elif messages:
            return score, "; ".join(messages)
        else:
            return score, f"Partial completion (score: {score:.2f})"
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_agent_add_high_urgency_issues_section(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Task Prompt: Navigate to the 'Bug Tracker' page and add a new bug report section immediately 
    AFTER the 'Medium Priority' section but BEFORE the 'Low Priority' heading. Create a heading_2 
    block with exact text 'High-Urgency Issues 🚨'. Below this, add exactly three unchecked to-do 
    blocks: '🔴 Memory leak in production causing server crashes', '🔴 Payment gateway timeout 
    affecting 15% of transactions', and '🔴 User data export fails for accounts over 1GB'. Then 
    insert a divider block. Finally, add a callout block with Red background and exact text 
    'These issues require immediate attention and should be resolved within 24 hours.'

    Validates:
    1. Bug Tracker page exists
    2. Medium Priority heading exists (reference point)
    3. Low Priority heading exists (reference point)
    4. heading_2 'High-Urgency Issues 🚨' exists between Medium Priority todos and Low Priority
    5. Three unchecked todos with exact text and 🔴 emoji exist after the new heading
    6. Divider block exists after the todos
    7. Red callout with exact warning text exists after divider
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Find Bug Tracker page using direct query
    try:
        bug_tracker_page = _find_page_by_title_direct(final_state_backend, "Bug Tracker")
        if not bug_tracker_page:
            errors.append("[X] Page 'Bug Tracker' not found")
        else:
            checks_passed.append("[C] Page 'Bug Tracker' found")

        page_id = bug_tracker_page.get("_id")
        if not page_id:
            errors.append("[X] Bug Tracker page has no _id")
        else:
            checks_passed.append("[C] Bug Tracker page has _id")

        # 2. Get all blocks for the page using direct query, sorted by order
        blocks = _get_blocks_for_page_direct(final_state_backend, page_id)
        if not blocks:
            errors.append("[X] Page 'Bug Tracker' has no content blocks")
        else:
            checks_passed.append("[C] Page 'Bug Tracker' has content blocks")

        blocks.sort(key=lambda b: b.get("order", 0))

        # 3. Find key reference blocks
        medium_priority_idx = None
        low_priority_idx = None
        high_urgency_idx = None
    
        for i, block in enumerate(blocks):
            block_type = block.get("type")
            content = block.get("content", "")
        
            if block_type in ["heading2", "heading_2"]:
                if "medium priority" in content.lower():
                    medium_priority_idx = i
                elif "low priority" in content.lower():
                    low_priority_idx = i
                elif "high-urgency issues" in content.lower() or "high urgency issues" in content.lower():
                    if "🚨" in content:
                        high_urgency_idx = i

        # 4. Validate reference points exist
        if medium_priority_idx is None:
            errors.append("[X] Could not find heading_2 'Medium Priority' on Bug Tracker page")
        else:
            checks_passed.append("[C] Could find heading_2 'Medium Priority' on Bug Tracker page")
    
        if low_priority_idx is None:
            errors.append("[X] Could not find heading_2 'Low Priority' on Bug Tracker page")
        else:
            checks_passed.append("[C] Could find heading_2 'Low Priority' on Bug Tracker page")

        # 5. Validate High-Urgency Issues heading exists
        if high_urgency_idx is None:
            errors.append("[X] Could not find heading_2 'High-Urgency Issues 🚨' on Bug Tracker page")
        else:
            checks_passed.append("[C] Could find heading_2 'High-Urgency Issues 🚨' on Bug Tracker page")

        # 6. Validate position: High-Urgency must be between Medium Priority todos and Low Priority
        # Find the last block belonging to Medium Priority section (before Low Priority)
        if high_urgency_idx <= medium_priority_idx:
            errors.append(f"[X] 'High-Urgency Issues 🚨' (index {high_urgency_idx}) should appear AFTER 'Medium Priority' (index {medium_priority_idx})")
        else:
            checks_passed.append(f"[C] 'High-Urgency Issues 🚨' (index {high_urgency_idx}) should appear AFTER 'Medium Priority' (index {medium_priority_idx})")
    
        if high_urgency_idx >= low_priority_idx:
            errors.append(f"[X] 'High-Urgency Issues 🚨' (index {high_urgency_idx}) should appear BEFORE 'Low Priority' (index {low_priority_idx})")
        else:
            checks_passed.append(f"[C] 'High-Urgency Issues 🚨' (index {high_urgency_idx}) should appear BEFORE 'Low Priority' (index {low_priority_idx})")

        # 7. Find and validate the three unchecked todos after High-Urgency heading
        expected_todos = [
            "🔴 Memory leak in production causing server crashes",
            "🔴 Payment gateway timeout affecting 15% of transactions",
            "🔴 User data export fails for accounts over 1GB"
        ]
    
        found_todos = []
        todo_indices = []
    
        for i in range(high_urgency_idx + 1, low_priority_idx):
            block = blocks[i]
            if block.get("type") == "todo":
                content = block.get("content", "")
                checked = block.get("properties", {}).get("checked", False)
            
                for expected in expected_todos:
                    # Check if content matches (case-insensitive, flexible matching)
                    if expected.lower() in content.lower() or content.lower() in expected.lower():
                        if "🔴" in content:
                            found_todos.append((content, checked))
                            todo_indices.append(i)
                            break

        if len(found_todos) < 3:
            errors.append(f"[X] Expected 3 todos with '🔴' emoji after 'High-Urgency Issues 🚨' heading, found {len(found_todos)}")
        else:
            checks_passed.append(f"[C] Found 3 todos with '🔴' emoji after 'High-Urgency Issues 🚨' heading as expected")

        # Validate todos are unchecked
        for content, checked in found_todos:
            if checked:
                errors.append(f"[X] Todo '{content[:50]}...' should be unchecked but is checked")
            else:
                checks_passed.append(f"[C] Todo '{content[:50]}...' should be unchecked but is checked")

        # 8. Find divider block after the todos but before Low Priority
        divider_idx = None
        last_todo_idx = max(todo_indices) if todo_indices else high_urgency_idx + 1
    
        for i in range(last_todo_idx + 1, low_priority_idx):
            if blocks[i].get("type") == "divider":
                divider_idx = i
                break

        if divider_idx is None:
            errors.append("[X] Could not find divider block after the new todos")
        else:
            checks_passed.append("[C] Could find divider block after the new todos")

        # 9. Find callout block after divider but before Low Priority
        callout_idx = None
        callout_block = None
    
        for i in range(divider_idx + 1, low_priority_idx):
            if blocks[i].get("type") == "callout":
                callout_idx = i
                callout_block = blocks[i]
                break

        if callout_idx is None:
            errors.append("[X] Could not find callout block after divider")
        else:
            checks_passed.append("[C] Could find callout block after divider")

        # 10. Validate callout has red background
        properties = callout_block.get("properties", {})
        background_color = properties.get("backgroundColor", "")
    
        if "red" not in background_color.lower():
            errors.append(f"[X] Callout background should be red, found '{background_color}'")
        else:
            checks_passed.append(f"[C] Callout background should be red, found '{background_color}'")

        # 11. Validate callout content
        callout_content = callout_block.get("content", "")
        expected_text = "These issues require immediate attention and should be resolved within 24 hours."
    
        if expected_text.lower() not in callout_content.lower():
            errors.append(f"[X] Callout text does not match expected. Expected: '{expected_text}', Found: '{callout_content}'")
        else:
            checks_passed.append(f"[C] Callout text match expected. Expected: '{expected_text}', Found: '{callout_content}'")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_agent_create_product_launch_tracker(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Task Prompt: Create a new page '🚀 2024 Product Launch Tracker' as a sibling to the 'Feature 
    Requests' page. First, fetch both 'Feature Requests' and 'Bug Tracker' pages to analyze their 
    to-do items. Structure the new page: heading_1 '🚀 2024 Product Launch Tracker', heading_2 
    '⚡ Launch Readiness Dashboard', then a callout with Red background if feature completion < 70% 
    or Green if >= 70%, containing 'Overall readiness: [FEATURE_PERCENTAGE]% features, 
    [BUG_PERCENTAGE]% bugs resolved'. Add heading_2 '📋 Pre-Launch Checklist' with these exact 
    to-do items (all unchecked): '⬜ Complete all high-priority features', '⬜ Resolve all critical 
    bugs', '⬜ Security audit passed', '⬜ Performance benchmarks met', '⬜ Documentation updated'. 
    Then heading_2 '📊 Detailed Status' with two subsections using heading_3: 'Feature Implementation 
    ([X]/[Y] complete)' showing all features from Feature Requests as a numbered list with ✅ or ⬜ 
    prefix based on their status, and 'Bug Resolution ([X]/[Y] resolved)' with all bugs similarly 
    listed. End with a toggle '🎯 Launch Criteria' containing a bulleted list: 'All critical bugs 
    resolved', 'Core features 100% complete', 'Security review approved'.

    Validates:
    1. Feature Requests page exists (for sibling validation)
    2. New page '🚀 2024 Product Launch Tracker' exists
    3. New page is sibling to Feature Requests (same parentId)
    4. heading_1 '🚀 2024 Product Launch Tracker' exists
    5. heading_2 '⚡ Launch Readiness Dashboard' exists
    6. Callout with correct color based on feature completion (<70% = red, >=70% = green)
    7. Callout contains percentage information
    8. heading_2 '📋 Pre-Launch Checklist' exists
    9. Five unchecked todos with exact text
    10. heading_2 '📊 Detailed Status' exists
    11. heading_3 'Feature Implementation' with count exists
    12. Numbered list with feature statuses
    13. heading_3 'Bug Resolution' with count exists
    14. Numbered list with bug statuses
    15. Toggle '🎯 Launch Criteria' exists
    16. Toggle contains bulleted list with launch criteria
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Find Feature Requests page (for sibling validation)
    try:
        feature_requests_page = _find_page_by_title(final_state_backend, "Feature Requests")
        if not feature_requests_page:
            errors.append("[X] Page 'Feature Requests' not found")
        else:
            checks_passed.append("[C] Page 'Feature Requests' found")

        feature_requests_parent_id = feature_requests_page.get("parentId")

        # 2. Find the new Product Launch Tracker page
        launch_tracker_page = _find_page_by_title(final_state_backend, "2024 Product Launch Tracker")
        if not launch_tracker_page:
            errors.append("[X] Page '🚀 2024 Product Launch Tracker' not found")
        else:
            checks_passed.append("[C] Page '🚀 2024 Product Launch Tracker' found")

        # 3. Validate page is sibling to Feature Requests
        if launch_tracker_page.get("parentId") != feature_requests_parent_id:
            errors.append(f"[X] Product Launch Tracker should be sibling to Feature Requests (same parentId: {feature_requests_parent_id}), but has parentId: {launch_tracker_page.get('parentId')}")
        else:
            checks_passed.append(f"[C] Product Launch Tracker should be sibling to Feature Requests (same parentId: {feature_requests_parent_id}), but has parentId: {launch_tracker_page.get('parentId')}")

        page_id = launch_tracker_page.get("_id")
        if not page_id:
            errors.append("[X] Product Launch Tracker page has no _id")
        else:
            checks_passed.append("[C] Product Launch Tracker page has _id")

        # Get blocks for the new page
        blocks = _get_blocks_for_page(final_state_backend, page_id)
        if not blocks:
            errors.append("[X] Page '2024 Product Launch Tracker' has no content blocks")
        else:
            checks_passed.append("[C] Page '2024 Product Launch Tracker' has content blocks")

        blocks.sort(key=lambda b: b.get("order", 0))

        # 4. Calculate feature and bug completion percentages from source pages
        # Get Feature Requests todos
        feature_requests_id = feature_requests_page.get("_id")
        # Get todo blocks using query-level filtering
        feature_todos = _get_todo_blocks(final_state_backend, feature_requests_id)
        feature_checked = len([t for t in feature_todos if t.get("properties", {}).get("checked", False)])
        feature_total = len(feature_todos)
        feature_percentage = (feature_checked / feature_total * 100) if feature_total > 0 else 0

        # Get Bug Tracker todos
        bug_tracker_page = _find_page_by_title(final_state_backend, "Bug Tracker")
        if bug_tracker_page:
            bug_tracker_id = bug_tracker_page.get("_id")
            # Get todo blocks using query-level filtering
            bug_todos = _get_todo_blocks(final_state_backend, bug_tracker_id)
            bug_checked = len([t for t in bug_todos if t.get("properties", {}).get("checked", False)])
            bug_total = len(bug_todos)
            bug_percentage = (bug_checked / bug_total * 100) if bug_total > 0 else 0
        else:
            bug_checked = 0
            bug_total = 0
            bug_percentage = 0

        # 5. Validate page structure
        # Find key headings
        main_heading_found = False
        dashboard_heading_found = False
        checklist_heading_found = False
        status_heading_found = False
        feature_impl_heading_found = False
        bug_resolution_heading_found = False
    
        callout_block = None
        checklist_todos = []
        toggle_block = None
    
        for i, block in enumerate(blocks):
            block_type = block.get("type")
            content = block.get("content", "")
        
            if block_type in ["heading1", "heading_1"]:
                if "2024 product launch tracker" in content.lower():
                    main_heading_found = True
        
            elif block_type in ["heading2", "heading_2"]:
                if "launch readiness dashboard" in content.lower() or "⚡" in content:
                    dashboard_heading_found = True
                elif "pre-launch checklist" in content.lower() or "📋" in content:
                    checklist_heading_found = True
                elif "detailed status" in content.lower() or "📊" in content:
                    status_heading_found = True
        
            elif block_type in ["heading3", "heading_3"]:
                if "feature implementation" in content.lower():
                    feature_impl_heading_found = True
                elif "bug resolution" in content.lower():
                    bug_resolution_heading_found = True
        
            elif block_type == "callout":
                if callout_block is None:
                    callout_block = block
        
            elif block_type == "todo":
                checklist_todos.append(block)
        
            elif block_type == "toggle":
                if "launch criteria" in content.lower() or "🎯" in content:
                    toggle_block = block

        # Validate main heading
        if not main_heading_found:
            errors.append("[X] Missing heading_1 '🚀 2024 Product Launch Tracker'")
        else:
            checks_passed.append("[C] has heading_1 '🚀 2024 Product Launch Tracker'")

        # Validate dashboard heading
        if not dashboard_heading_found:
            errors.append("[X] Missing heading_2 '⚡ Launch Readiness Dashboard'")
        else:
            checks_passed.append("[C] has heading_2 '⚡ Launch Readiness Dashboard'")

        # Validate callout exists and has correct color
        if callout_block is None:
            errors.append("[X] Missing callout block for launch readiness status")
        else:
            checks_passed.append("[C] has callout block for launch readiness status")

        callout_props = callout_block.get("properties", {})
        background_color = callout_props.get("backgroundColor", "")
    
        # Feature completion < 70% should be red, >= 70% should be green
        expected_color = "red" if feature_percentage < 70 else "green"
    
        if expected_color not in background_color.lower():
            errors.append(f"[X] Callout should be {expected_color} (feature completion: {feature_percentage:.1f}%), but has background: '{background_color}'")
        else:
            checks_passed.append(f"[C] Callout should be {expected_color} (feature completion: {feature_percentage:.1f}%), but has background: '{background_color}'")

        # Validate callout contains percentage info
        callout_content = callout_block.get("content", "")
        if "overall readiness" not in callout_content.lower() and "%" not in callout_content:
            errors.append(f"[X] Callout should contain 'Overall readiness' with percentages, found: '{callout_content[:100]}'")
        else:
            checks_passed.append(f"[C] Callout should contain 'Overall readiness' with percentages, found: '{callout_content[:100]}'")

        # Validate Pre-Launch Checklist heading
        if not checklist_heading_found:
            errors.append("[X] Missing heading_2 '📋 Pre-Launch Checklist'")
        else:
            checks_passed.append("[C] has heading_2 '📋 Pre-Launch Checklist'")

        # Validate 5 checklist todos
        expected_checklist_items = [
            "complete all high-priority features",
            "resolve all critical bugs",
            "security audit passed",
            "performance benchmarks met",
            "documentation updated"
        ]
    
        found_checklist_items = 0
        for todo in checklist_todos:
            todo_content = todo.get("content", "").lower()
            for expected in expected_checklist_items:
                if expected in todo_content:
                    found_checklist_items += 1
                    break

        if found_checklist_items < 5:
            errors.append(f"[X] Expected 5 pre-launch checklist todos, found {found_checklist_items} matching items")
        else:
            checks_passed.append(f"[C] Found 5 pre-launch checklist todos as expected")

        # Validate Detailed Status heading
        if not status_heading_found:
            errors.append("[X] Missing heading_2 '📊 Detailed Status'")
        else:
            checks_passed.append("[C] has heading_2 '📊 Detailed Status'")

        # Validate Feature Implementation heading_3
        if not feature_impl_heading_found:
            errors.append("[X] Missing heading_3 'Feature Implementation ([X]/[Y] complete)'")
        else:
            checks_passed.append("[C] has heading_3 'Feature Implementation ([X]/[Y] complete)'")

        # Validate Bug Resolution heading_3
        if not bug_resolution_heading_found:
            errors.append("[X] Missing heading_3 'Bug Resolution ([X]/[Y] resolved)'")
        else:
            checks_passed.append("[C] has heading_3 'Bug Resolution ([X]/[Y] resolved)'")

        # Validate toggle block exists
        if toggle_block is None:
            errors.append("[X] Missing toggle '🎯 Launch Criteria'")
        else:
            checks_passed.append("[C] has toggle '🎯 Launch Criteria'")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_agent_reorganize_company_handbook(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Task Prompt: On the 'Company Handbook' page, perform a complex reorganization. First, swap the 
    positions of the 'Our Values' section (including all its bullet points) with the 'Benefits' 
    section (including all numbered list items). The 'Work Policies' section should remain in its 
    middle position. Then, immediately after the newly positioned 'Benefits' section but before 
    'Work Policies', insert a new heading_2 '🌟 Employee Recognition Program' followed by a quote 
    block with text 'Excellence deserves recognition - we celebrate achievements big and small.' 
    Add three bulletedList blocks: '🏆 Monthly MVP award with $500 bonus', '🎯 Quarterly team 
    achievement celebrations', '📈 Annual performance bonuses up to 20% of salary'. Finally, add 
    a divider block before the 'Work Policies' section.

    Validates:
    1. Company Handbook page exists
    2. 'Benefits' section now appears before 'Work Policies' (was originally after)
    3. 'Benefits' has 4 numbered list items with original content preserved
    4. New heading_2 '🌟 Employee Recognition Program' exists after Benefits, before Work Policies
    5. Quote block with exact text exists after Recognition heading
    6. Three bulletedList blocks with exact content and emojis exist
    7. Divider block exists before 'Work Policies'
    8. 'Work Policies' section remains in middle position
    9. 'Our Values' section now appears after 'Work Policies' (at the bottom)
    10. 'Our Values' has 3 bullet points with original content preserved
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Find Company Handbook page using direct query
    try:
        handbook_page = _find_page_by_title_direct(final_state_backend, "Company Handbook")
        if not handbook_page:
            errors.append("[X] Page 'Company Handbook' not found")
        else:
            checks_passed.append("[C] Page 'Company Handbook' found")

        page_id = handbook_page.get("_id")
        if not page_id:
            errors.append("[X] Company Handbook page has no _id")
        else:
            checks_passed.append("[C] Company Handbook page has _id")

        # 2. Get all blocks for the page using direct query, sorted by order
        blocks = _get_blocks_for_page_direct(final_state_backend, page_id)
        if not blocks:
            errors.append("[X] Page 'Company Handbook' has no content blocks")
        else:
            checks_passed.append("[C] Page 'Company Handbook' has content blocks")

        blocks.sort(key=lambda b: b.get("order", 0))

        # 3. Find key section headings
        benefits_idx = None
        work_policies_idx = None
        our_values_idx = None
        recognition_idx = None
    
        for i, block in enumerate(blocks):
            block_type = block.get("type")
            content = block.get("content", "")
        
            if block_type in ["heading2", "heading_2"]:
                content_lower = content.lower()
                if "benefits" in content_lower:
                    benefits_idx = i
                elif "work policies" in content_lower:
                    work_policies_idx = i
                elif "our values" in content_lower:
                    our_values_idx = i
                elif "employee recognition program" in content_lower or "🌟" in content:
                    recognition_idx = i

        # 4. Validate all required headings exist
        if benefits_idx is None:
            errors.append("[X] Could not find heading_2 'Benefits' on Company Handbook page")
        else:
            checks_passed.append("[C] Could find heading_2 'Benefits' on Company Handbook page")
    
        if work_policies_idx is None:
            errors.append("[X] Could not find heading_2 'Work Policies' on Company Handbook page")
        else:
            checks_passed.append("[C] Could find heading_2 'Work Policies' on Company Handbook page")
    
        if our_values_idx is None:
            errors.append("[X] Could not find heading_2 'Our Values' on Company Handbook page")
        else:
            checks_passed.append("[C] Could find heading_2 'Our Values' on Company Handbook page")
    
        if recognition_idx is None:
            errors.append("[X] Could not find new heading_2 '🌟 Employee Recognition Program' on Company Handbook page")
        else:
            checks_passed.append("[C] Could find new heading_2 '🌟 Employee Recognition Program' on Company Handbook page")

        # 5. Validate section ordering: Benefits < Recognition < Work Policies < Our Values
        if benefits_idx >= work_policies_idx:
            errors.append(f"[X] 'Benefits' (index {benefits_idx}) should appear BEFORE 'Work Policies' (index {work_policies_idx})")
        else:
            checks_passed.append(f"[C] 'Benefits' (index {benefits_idx}) should appear BEFORE 'Work Policies' (index {work_policies_idx})")
    
        if recognition_idx <= benefits_idx:
            errors.append(f"[X] 'Employee Recognition Program' (index {recognition_idx}) should appear AFTER 'Benefits' (index {benefits_idx})")
        else:
            checks_passed.append(f"[C] 'Employee Recognition Program' (index {recognition_idx}) should appear AFTER 'Benefits' (index {benefits_idx})")
    
        if recognition_idx >= work_policies_idx:
            errors.append(f"[X] 'Employee Recognition Program' (index {recognition_idx}) should appear BEFORE 'Work Policies' (index {work_policies_idx})")
        else:
            checks_passed.append(f"[C] 'Employee Recognition Program' (index {recognition_idx}) should appear BEFORE 'Work Policies' (index {work_policies_idx})")
    
        if our_values_idx <= work_policies_idx:
            errors.append(f"[X] 'Our Values' (index {our_values_idx}) should appear AFTER 'Work Policies' (index {work_policies_idx})")
        else:
            checks_passed.append(f"[C] 'Our Values' (index {our_values_idx}) should appear AFTER 'Work Policies' (index {work_policies_idx})")

        # 6. Validate Benefits section has 4 numbered list items
        benefits_items = []
        expected_benefits = [
            "comprehensive health insurance",
            "401(k) matching",
            "annual learning stipend",
            "home office setup allowance"
        ]
    
        for i in range(benefits_idx + 1, recognition_idx):
            block = blocks[i]
            if block.get("type") == "numberedList":
                content = block.get("content", "").lower()
                benefits_items.append(content)

        if len(benefits_items) < 4:
            errors.append(f"[X] 'Benefits' section should have 4 numbered list items, found {len(benefits_items)}")
        else:
            checks_passed.append(f"[C] 'Benefits' section should have 4 numbered list items, found {len(benefits_items)}")

        # Verify benefits content is preserved
        found_benefits = 0
        for expected in expected_benefits:
            for item in benefits_items:
                if expected in item:
                    found_benefits += 1
                    break

        if found_benefits < 4:
            errors.append(f"[X] Benefits items not preserved correctly. Found {found_benefits}/4 expected items")
        else:
            checks_passed.append(f"[C] Benefits items preserved correctly. Found {found_benefits}/4 expected items")

        # 7. Validate quote block exists after Recognition heading
        quote_found = False
        expected_quote = "excellence deserves recognition - we celebrate achievements big and small"
    
        for i in range(recognition_idx + 1, work_policies_idx):
            block = blocks[i]
            if block.get("type") == "quote":
                content = block.get("content", "").lower()
                if expected_quote in content:
                    quote_found = True
                    break

        if not quote_found:
            errors.append("[X] Missing quote block with text 'Excellence deserves recognition - we celebrate achievements big and small.'")
        else:
            checks_passed.append("[C] has quote block with text 'Excellence deserves recognition - we celebrate achievements big and small.'")

        # 8. Validate three bulletedList blocks with exact content
        expected_recognition_items = [
            "🏆 monthly mvp award with $500 bonus",
            "🎯 quarterly team achievement celebrations",
            "📈 annual performance bonuses up to 20% of salary"
        ]
    
        found_recognition_items = 0
        for i in range(recognition_idx + 1, work_policies_idx):
            block = blocks[i]
            if block.get("type") == "bulletedList":
                content = block.get("content", "").lower()
                for expected in expected_recognition_items:
                    if expected.split(" ", 1)[1] in content:  # Check without emoji
                        found_recognition_items += 1
                        break

        if found_recognition_items < 3:
            errors.append(f"[X] Expected 3 recognition bulletedList items, found {found_recognition_items}")
        else:
            checks_passed.append(f"[C] Found 3 recognition bulletedList items as expected")

        # 9. Validate divider exists before Work Policies
        divider_found = False
        for i in range(recognition_idx + 1, work_policies_idx):
            if blocks[i].get("type") == "divider":
                divider_found = True
                break

        if not divider_found:
            errors.append("[X] Missing divider block before 'Work Policies' section")
        else:
            checks_passed.append("[C] has divider block before 'Work Policies' section")

        # 10. Validate Our Values section has 3 bullet points with preserved content
        expected_values = [
            "customer first",
            "excellence",
            "collaboration"
        ]
    
        values_items = []
        for i in range(our_values_idx + 1, len(blocks)):
            block = blocks[i]
            if block.get("type") == "bulletedList":
                content = block.get("content", "").lower()
                values_items.append(content)
            elif block.get("type") in ["heading2", "heading_2"]:
                # Stop at next section
                break

        if len(values_items) < 3:
            errors.append(f"[X] 'Our Values' section should have 3 bulleted items, found {len(values_items)}")
        else:
            checks_passed.append(f"[C] 'Our Values' section should have 3 bulleted items, found {len(values_items)}")

        found_values = 0
        for expected in expected_values:
            for item in values_items:
                if expected in item:
                    found_values += 1
                    break

        if found_values < 3:
            errors.append(f"[X] Our Values items not preserved correctly. Found {found_values}/3 expected items")
        else:
            checks_passed.append(f"[C] Our Values items preserved correctly. Found {found_values}/3 expected items")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_agent_create_external_resources_audit_report(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Task: Navigate to 'External Resources & Links' page and create a comprehensive link audit report 
    at the top of the page, before all existing content.
    
    Prompt: "Navigate to 'External Resources & Links' page and create a comprehensive link audit report 
    at the top of the page, before all existing content. Add heading_1 '🔍 Resource Audit Report - [TODAY'S DATE]'. 
    Count all bookmark blocks on the page and group them by their section headings. Create a callout block 
    with Orange background containing heading_3 '📊 Link Distribution Analysis' followed by a paragraph 
    showing 'Total resources: [X] links across [Y] categories'. For each section (Documentation, Tools, Learning), 
    add a heading_3 '[Section Name] Analysis' followed by a bulleted list showing: '• Link count: [X]', 
    '• Duplicates found: [Y]' (count bookmarks with identical URLs), '• Most common domain: [domain]'. 
    After the analysis, add a divider, then a heading_2 '⚠️ Duplicate Resources' and list each duplicate 
    bookmark URL with its locations using todo blocks (unchecked) formatted as 
    '☐ Remove duplicate: [URL] (appears in [Section1], [Section2])'."
    
    Validates:
    1. Find 'External Resources & Links' page
    2. Audit report appears at the TOP (before original content)
    3. Has heading1 containing '🔍 Resource Audit Report' and a date
    4. Has callout with orange_background containing '📊 Link Distribution Analysis'
    5. Callout/paragraph shows 'Total resources: 15' and '3 categories'
    6. Has section analysis headings (Documentation, Tools, Learning) with bulletedList
    7. Has divider block
    8. Has heading2 '⚠️ Duplicate Resources'
    9. Has unchecked todo blocks listing duplicate URLs
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Find 'External Resources & Links' page
    try:
        resources_page = _find_page_by_title(final_state_backend, "External Resources & Links")
        if not resources_page:
            errors.append("[X] Page 'External Resources & Links' not found")
        else:
            checks_passed.append("[C] Page 'External Resources & Links' found")
    
        page_id = resources_page.get("_id")
        if not page_id:
            errors.append("[X] External Resources & Links page has no _id")
        else:
            checks_passed.append("[C] External Resources & Links page has _id")
    
        # Get all blocks for the page sorted by order
        blocks = _get_blocks_for_page(final_state_backend, page_id)
        if not blocks:
            errors.append("[X] Page 'External Resources & Links' has no content blocks")
        else:
            checks_passed.append("[C] Page 'External Resources & Links' has content blocks")
    
        blocks.sort(key=lambda b: b.get("order", 0))
    
        # 2. Find original content start (first heading that's Documentation/Tools/Learning or "External Resources")
        original_first_block_order = None
        for block in blocks:
            content_lower = block.get("content", "").lower()
            if block.get("type") in ["heading1", "heading2"] and any(
                kw in content_lower for kw in ["external resources", "documentation", "tools", "learning"]
            ):
                # Check if this looks like original content (not audit report)
                if "audit" not in content_lower and "analysis" not in content_lower:
                    original_first_block_order = block.get("order", 0)
                    break
    
        # Validation flags
        has_audit_heading = False
        has_orange_callout = False
        has_total_resources = False
        has_documentation_analysis = False
        has_tools_analysis = False
        has_learning_analysis = False
        has_documentation_details = False  # link count, duplicates, domain
        has_tools_details = False
        has_learning_details = False
        has_divider = False
        has_duplicate_heading = False
        has_duplicate_todos = False
        audit_heading_order = None
        current_analysis_section = None
    
        for block in blocks:
            block_type = block.get("type", "")
            content = block.get("content", "")
            content_lower = content.lower()
            props = block.get("properties", {})
            order = block.get("order", 0)
        
            # 3. Check for audit report heading at top
            if block_type == "heading1" and "resource audit report" in content_lower:
                has_audit_heading = True
                audit_heading_order = order
                # Verify it's before original content
                if original_first_block_order is not None and order >= original_first_block_order:
                    errors.append("[X] Audit report heading must appear BEFORE existing content")
                else:
                    checks_passed.append("[C] Audit report heading must appear BEFORE existing content")
        
            # 4. Check for orange callout with link distribution analysis
            if block_type == "callout":
                bg_color = props.get("backgroundColor", "")
                if "orange" in bg_color.lower():
                    if "link distribution analysis" in content_lower or "📊" in content:
                        has_orange_callout = True
        
            # 5. Check for total resources paragraph
            if "total resources" in content_lower:
                # Check for count around 15 and categories around 3
                if any(str(n) in content for n in range(12, 18)):  # Allow some flexibility
                    has_total_resources = True
        
            # 6. Check for section analysis headings and track current section
            if block_type == "heading3":
                if "documentation" in content_lower and "analysis" in content_lower:
                    has_documentation_analysis = True
                    current_analysis_section = "documentation"
                elif "tools" in content_lower and "analysis" in content_lower:
                    has_tools_analysis = True
                    current_analysis_section = "tools"
                elif "learning" in content_lower and "analysis" in content_lower:
                    has_learning_analysis = True
                    current_analysis_section = "learning"
                else:
                    current_analysis_section = None
        
            # Check for section analysis details (link count, duplicates, domain) in bulleted lists
            if block_type in ["bulletedList", "bulletedListItem", "paragraph"] and current_analysis_section:
                has_link_count = "link count" in content_lower
                has_duplicates = "duplicates" in content_lower or "duplicate" in content_lower
                has_domain = "domain" in content_lower or "most common" in content_lower
            
                if has_link_count or has_duplicates or has_domain:
                    if current_analysis_section == "documentation":
                        has_documentation_details = True
                    elif current_analysis_section == "tools":
                        has_tools_details = True
                    elif current_analysis_section == "learning":
                        has_learning_details = True
        
            # 7. Check for divider
            if block_type == "divider":
                has_divider = True
        
            # 8. Check for duplicate resources heading
            if block_type == "heading2" and "duplicate" in content_lower and ("resources" in content_lower or "⚠️" in content):
                has_duplicate_heading = True
        
            # 9. Check for todo blocks with duplicate URLs
            if block_type == "todo":
                checked = props.get("checked", False)
                if not checked and ("remove duplicate" in content_lower or "appears in" in content_lower or any(
                    url in content_lower for url in ["react.dev", "typescriptlang", "mozilla", "stackoverflow", "github"]
                )):
                    has_duplicate_todos = True
    
        # Validate all checks
        if not has_audit_heading:
            errors.append("[X] Missing heading1 '🔍 Resource Audit Report - [DATE]'")
        else:
            checks_passed.append("[C] has heading1 '🔍 Resource Audit Report - [DATE]'")
    
        if not has_orange_callout:
            errors.append("[X] Missing callout with orange background containing '📊 Link Distribution Analysis'")
        else:
            checks_passed.append("[C] has callout with orange background containing '📊 Link Distribution Analysis'")
    
        if not has_total_resources:
            errors.append("[X] Missing paragraph showing total resources count and categories")
        else:
            checks_passed.append("[C] has paragraph showing total resources count and categories")
    
        if not has_documentation_analysis:
            errors.append("[X] Missing heading3 'Documentation Analysis'")
        else:
            checks_passed.append("[C] has heading3 'Documentation Analysis'")
    
        if not has_tools_analysis:
            errors.append("[X] Missing heading3 'Tools Analysis'")
        else:
            checks_passed.append("[C] has heading3 'Tools Analysis'")
    
        if not has_learning_analysis:
            errors.append("[X] Missing heading3 'Learning Analysis'")
        else:
            checks_passed.append("[C] has heading3 'Learning Analysis'")
    
        # Check for section analysis details (link count, duplicates, domain)
        if not has_documentation_details:
            errors.append("[X] Documentation Analysis section missing details (link count, duplicates found, most common domain)")
        else:
            checks_passed.append("[C] Documentation Analysis section has details (link count, duplicates found, most common domain)")
    
        if not has_tools_details:
            errors.append("[X] Tools Analysis section missing details (link count, duplicates found, most common domain)")
        else:
            checks_passed.append("[C] Tools Analysis section has details (link count, duplicates found, most common domain)")
    
        if not has_learning_details:
            errors.append("[X] Learning Analysis section missing details (link count, duplicates found, most common domain)")
        else:
            checks_passed.append("[C] Learning Analysis section has details (link count, duplicates found, most common domain)")
    
        if not has_divider:
            errors.append("[X] Missing divider block after analysis sections")
        else:
            checks_passed.append("[C] has divider block after analysis sections")
    
        if not has_duplicate_heading:
            errors.append("[X] Missing heading2 '⚠️ Duplicate Resources'")
        else:
            checks_passed.append("[C] has heading2 '⚠️ Duplicate Resources'")
    
        if not has_duplicate_todos:
            errors.append("[X] Missing unchecked todo blocks listing duplicate URLs")
        else:
            checks_passed.append("[C] has unchecked todo blocks listing duplicate URLs")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_agent_add_q1_goals_progress_update(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Task: On the 'Q1 Goals' page, perform a detailed progress update after 'Key Results' heading.
    
    Prompt: "On the 'Q1 Goals' page (under Project Roadmap), perform a detailed progress update. 
    First, immediately AFTER the 'Key Results' heading but BEFORE any existing content beneath it, 
    insert a heading_3 '📊 Progress Update - [Today's Date]'. Below this, add a callout with Green 
    background and checkmark icon if more than 50% of todos are checked, or Red background with X icon 
    if less. The callout text should be 'Q1 Performance: [STATUS]' where STATUS is 'On Track' (>50%) 
    or 'Behind Schedule' (≤50%). Then add a divider followed by heading_3 '🎯 Detailed Metrics'. 
    Under this, create exactly four paragraph blocks: '• Total Objectives: [X]' (count all todos), 
    '• Completed: [Y] ✅' (checked todos), '• In Progress: [Z] 🔄' (unchecked todos), 
    '• Success Rate: [W]% 📈'. Finally, add a quote block with text 
    'Next review scheduled for: [date 7 days from today]'."
    
    Validates:
    1. Find 'Q1 Goals' page under 'Project Roadmap'
    2. Find 'Key Results' heading
    3. Progress update content appears AFTER 'Key Results' but BEFORE original content beneath it
    4. Has heading3 '📊 Progress Update' with a date
    5. Has callout with appropriate color (Green if >50%, Red if ≤50%)
    6. Callout text contains 'Q1 Performance: On Track' or 'Behind Schedule'
    7. Has divider
    8. Has heading3 '🎯 Detailed Metrics'
    9. Has 4 paragraphs with accurate counts
    10. Has quote block with future date
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Find 'Q1 Goals' page using direct query
    try:
        q1_page = _find_page_by_title_direct(backend, "Q1 Goals")
        if not q1_page:
            errors.append("[X] Page 'Q1 Goals' not found")
        else:
            checks_passed.append("[C] Page 'Q1 Goals' found")
    
        page_id = q1_page.get("_id")
        if not page_id:
            errors.append("[X] Q1 Goals page has no _id")
        else:
            checks_passed.append("[C] Q1 Goals page has _id")
    
        # Verify it's under Project Roadmap using direct query
        parent_id = q1_page.get("parentId")
        if parent_id:
            roadmap_page = _find_page_by_title_direct(backend, "Project Roadmap")
            if roadmap_page and roadmap_page.get("_id") != parent_id:
                errors.append("[X] Q1 Goals is not under Project Roadmap")
            else:
                checks_passed.append("[C] Q1 Goals is under Project Roadmap")
    
        # Get all blocks for the page using direct query
        blocks = _get_blocks_for_page_direct(backend, page_id)
        if not blocks:
            errors.append("[X] Page 'Q1 Goals' has no content blocks")
        else:
            checks_passed.append("[C] Page 'Q1 Goals' has content blocks")
    
        blocks.sort(key=lambda b: b.get("order", 0))
    
        # Count todos to determine expected callout color
        todos = [b for b in blocks if b.get("type") == "todo"]
        checked_count = sum(1 for t in todos if t.get("properties", {}).get("checked", False))
        total_todos = len(todos)
        completion_rate = (checked_count / total_todos * 100) if total_todos > 0 else 0
        expected_on_track = completion_rate > 50
    
        # Find 'Key Results' heading
        key_results_order = None
        for block in blocks:
            if block.get("type") in ["heading1", "heading2", "heading3"]:
                content_lower = block.get("content", "").lower()
                if "key results" in content_lower:
                    key_results_order = block.get("order", 0)
                    break
    
        if key_results_order is None:
            errors.append("[X] Heading 'Key Results' not found")
        else:
            checks_passed.append("[C] Heading 'Key Results' found")
    
        # Validation flags
        has_progress_heading = False
        has_callout = False
        callout_color_correct = False
        callout_status_correct = False
        callout_icon_correct = False
        has_divider = False
        has_metrics_heading = False
        has_total_paragraph = False
        has_completed_paragraph = False
        has_in_progress_paragraph = False
        has_success_rate_paragraph = False
        has_quote = False
    
        for block in blocks:
            block_type = block.get("type", "")
            content = block.get("content", "")
            content_lower = content.lower()
            props = block.get("properties", {})
            order = block.get("order", 0)
        
            # Only check blocks after Key Results
            if order <= key_results_order:
                continue
        
            # 4. Check for progress update heading
            if block_type == "heading3" and "progress update" in content_lower:
                has_progress_heading = True
        
            # 5-6. Check for callout with correct color, icon, and status
            if block_type == "callout" and "q1 performance" in content_lower:
                has_callout = True
                bg_color = props.get("backgroundColor", "").lower()
                icon = props.get("icon", "")
            
                if expected_on_track:
                    if "green" in bg_color:
                        callout_color_correct = True
                    if "on track" in content_lower:
                        callout_status_correct = True
                    # Check for checkmark icon (various representations)
                    if any(c in icon for c in ["✓", "✔", "☑", "✅", "check"]) or "✓" in content or "✔" in content or "✅" in content:
                        callout_icon_correct = True
                else:
                    if "red" in bg_color:
                        callout_color_correct = True
                    if "behind schedule" in content_lower:
                        callout_status_correct = True
                    # Check for X icon (various representations)
                    if any(c in icon for c in ["✗", "✘", "☒", "❌", "x", "X"]) or "✗" in content or "✘" in content or "❌" in content:
                        callout_icon_correct = True
        
            # 7. Check for divider
            if block_type == "divider":
                has_divider = True
        
            # 8. Check for metrics heading
            if block_type == "heading3" and "detailed metrics" in content_lower:
                has_metrics_heading = True
        
            # 9. Check for metric paragraphs
            if block_type == "paragraph":
                if "total objectives" in content_lower:
                    has_total_paragraph = True
                elif "completed" in content_lower and "✅" in content:
                    has_completed_paragraph = True
                elif "in progress" in content_lower and "🔄" in content:
                    has_in_progress_paragraph = True
                elif "success rate" in content_lower and "📈" in content:
                    has_success_rate_paragraph = True
        
            # 10. Check for quote block
            if block_type == "quote" and "next review" in content_lower:
                has_quote = True
    
        # Validate all checks
        if not has_progress_heading:
            errors.append("[X] Missing heading3 '📊 Progress Update - [Date]'")
        else:
            checks_passed.append("[C] has heading3 '📊 Progress Update - [Date]'")
    
        if not has_callout:
            errors.append("[X] Missing callout with 'Q1 Performance' status")
        else:
            checks_passed.append("[C] has callout with 'Q1 Performance' status")
    
        if not callout_color_correct:
            expected_color = "Green" if expected_on_track else "Red"
            errors.append(f"[X] Callout should have {expected_color} background based on {completion_rate:.1f}% completion")
        else:
            checks_passed.append(f"[C] Callout should have {expected_color} background based on {completion_rate:.1f}% completion")
    
        if not callout_status_correct:
            expected_status = "On Track" if expected_on_track else "Behind Schedule"
            errors.append(f"[X] Callout should show '{expected_status}' based on {completion_rate:.1f}% completion")
        else:
            checks_passed.append(f"[C] Callout should show '{expected_status}' based on {completion_rate:.1f}% completion")
    
        if not callout_icon_correct:
            expected_icon = "checkmark" if expected_on_track else "X"
            errors.append(f"[X] Callout should have {expected_icon} icon based on {completion_rate:.1f}% completion")
        else:
            checks_passed.append(f"[C] Callout should have {expected_icon} icon based on {completion_rate:.1f}% completion")
    
        if not has_divider:
            errors.append("[X] Missing divider after callout")
        else:
            checks_passed.append("[C] has divider after callout")
    
        if not has_metrics_heading:
            errors.append("[X] Missing heading3 '🎯 Detailed Metrics'")
        else:
            checks_passed.append("[C] has heading3 '🎯 Detailed Metrics'")
    
        if not has_total_paragraph:
            errors.append("[X] Missing paragraph '• Total Objectives: [X]'")
        else:
            checks_passed.append("[C] has paragraph '• Total Objectives: [X]'")
    
        if not has_completed_paragraph:
            errors.append("[X] Missing paragraph '• Completed: [Y] ✅'")
        else:
            checks_passed.append("[C] has paragraph '• Completed: [Y] ✅'")
    
        if not has_in_progress_paragraph:
            errors.append("[X] Missing paragraph '• In Progress: [Z] 🔄'")
        else:
            checks_passed.append("[C] has paragraph '• In Progress: [Z] 🔄'")
    
        if not has_success_rate_paragraph:
            errors.append("[X] Missing paragraph '• Success Rate: [W]% 📈'")
        else:
            checks_passed.append("[C] has paragraph '• Success Rate: [W]% 📈'")
    
        if not has_quote:
            errors.append("[X] Missing quote block with 'Next review scheduled for: [date]'")
        else:
            checks_passed.append("[C] has quote block with 'Next review scheduled for: [date]'")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_agent_add_30_day_milestone_checklist(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Task: Navigate to 'Onboarding Guide' page and insert 30-Day Milestone Checklist after First Week Goals.
    
    Prompt: "Navigate to the 'Onboarding Guide' page. Insert a new section immediately AFTER the 
    'First Week Goals' section but BEFORE any subsequent content. Add heading_2 '🎯 30-Day Milestone Checklist' 
    followed by a paragraph with text 'Track your progress through the first month with these key milestones.' 
    Then create three subsections: First, heading_3 '📅 Week 2-3 Objectives' with four unchecked todo blocks: 
    '🔧 Complete first code review', '📝 Document your first feature', '🤝 Shadow a senior developer', 
    '💡 Propose one process improvement'. Second, heading_3 '📅 Week 4 Objectives' with three unchecked todos: 
    '🚀 Deploy to staging environment', '📊 Present learnings to team', '✨ Take ownership of a small feature'. 
    Finally, add a callout with Blue background and info icon containing bold text 
    'Pro tip: Schedule a check-in with your manager after completing each week's objectives!'"
    
    Validates:
    1. Find 'Onboarding Guide' page
    2. Find 'First Week Goals' heading
    3. New section appears AFTER First Week Goals heading but BEFORE existing content beneath it
    4. Has heading2 '🎯 30-Day Milestone Checklist'
    5. Has intro paragraph
    6. Has heading3 '📅 Week 2-3 Objectives'
    7. Has 4 unchecked todos for Week 2-3 with correct content
    8. Has heading3 '📅 Week 4 Objectives'
    9. Has 3 unchecked todos for Week 4 with correct content
    10. Has blue callout with pro tip
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Find 'Onboarding Guide' page using direct query
    try:
        onboarding_page = _find_page_by_title_direct(backend, "Onboarding Guide")
        if not onboarding_page:
            errors.append("[X] Page 'Onboarding Guide' not found")
        else:
            checks_passed.append("[C] Page 'Onboarding Guide' found")
    
        page_id = onboarding_page.get("_id")
        if not page_id:
            errors.append("[X] Onboarding Guide page has no _id")
        else:
            checks_passed.append("[C] Onboarding Guide page has _id")
    
        # Get all blocks for the page using direct query
        blocks = _get_blocks_for_page_direct(backend, page_id)
        if not blocks:
            errors.append("[X] Page 'Onboarding Guide' has no content blocks")
        else:
            checks_passed.append("[C] Page 'Onboarding Guide' has content blocks")
    
        blocks.sort(key=lambda b: b.get("order", 0))
    
        # 2. Find 'First Week Goals' heading
        first_week_order = None
        for block in blocks:
            if block.get("type") in ["heading1", "heading2", "heading3"]:
                content_lower = block.get("content", "").lower()
                if "first week goals" in content_lower:
                    first_week_order = block.get("order", 0)
                    break
    
        if first_week_order is None:
            errors.append("[X] Heading 'First Week Goals' not found")
        else:
            checks_passed.append("[C] Heading 'First Week Goals' found")
    
        # Validation flags
        has_milestone_heading = False
        milestone_heading_order = None
        has_intro_paragraph = False
        has_week_2_3_heading = False
        has_week_4_heading = False
        has_blue_callout = False
    
        week_2_3_todos = []
        week_4_todos = []
        current_section = None
    
        for block in blocks:
            block_type = block.get("type", "")
            content = block.get("content", "")
            content_lower = content.lower()
            props = block.get("properties", {})
            order = block.get("order", 0)
        
            # 4. Check for milestone checklist heading
            if block_type == "heading2" and "30-day milestone checklist" in content_lower:
                has_milestone_heading = True
                milestone_heading_order = order
                # Verify it's after First Week Goals
                if order <= first_week_order:
                    errors.append("[X] 30-Day Milestone Checklist heading must appear AFTER 'First Week Goals'")
                else:
                    checks_passed.append("[C] 30-Day Milestone Checklist heading must appear AFTER 'First Week Goals'")
        
            # 5. Check for intro paragraph
            if block_type == "paragraph" and "track your progress" in content_lower and "first month" in content_lower:
                has_intro_paragraph = True
        
            # 6. Check for Week 2-3 heading
            if block_type == "heading3" and "week 2-3" in content_lower and "objectives" in content_lower:
                has_week_2_3_heading = True
                current_section = "week_2_3"
        
            # 8. Check for Week 4 heading
            if block_type == "heading3" and "week 4" in content_lower and "objectives" in content_lower:
                has_week_4_heading = True
                current_section = "week_4"
        
            # Collect todos by section
            if block_type == "todo":
                checked = props.get("checked", False)
                if not checked:
                    if current_section == "week_2_3":
                        week_2_3_todos.append(content_lower)
                    elif current_section == "week_4":
                        week_4_todos.append(content_lower)
        
            # Reset section tracking if we hit a callout (end of todos)
            if block_type == "callout":
                bg_color = props.get("backgroundColor", "").lower()
                icon = props.get("icon", "")
                # Check for blue background with info icon and pro tip content
                if "blue" in bg_color and "pro tip" in content_lower:
                    # Check for info icon (various representations: ℹ️, 💡, or other info-related icons)
                    has_info_icon = any(c in icon for c in ["ℹ", "ℹ️", "info", "💡", "i", "📌"]) or any(c in content for c in ["ℹ", "ℹ️", "💡"])
                    if has_info_icon:
                        has_blue_callout = True
                current_section = None
    
        # Validate all checks
        if not has_milestone_heading:
            errors.append("[X] Missing heading2 '🎯 30-Day Milestone Checklist'")
        else:
            checks_passed.append("[C] has heading2 '🎯 30-Day Milestone Checklist'")
    
        if not has_intro_paragraph:
            errors.append("[X] Missing intro paragraph about tracking progress through first month")
        else:
            checks_passed.append("[C] has intro paragraph about tracking progress through first month")
    
        if not has_week_2_3_heading:
            errors.append("[X] Missing heading3 '📅 Week 2-3 Objectives'")
        else:
            checks_passed.append("[C] has heading3 '📅 Week 2-3 Objectives'")
    
        # 7. Validate Week 2-3 todos (4 required)
        required_week_2_3 = ["code review", "document", "shadow", "process improvement"]
        found_week_2_3 = 0
        for req in required_week_2_3:
            for todo in week_2_3_todos:
                if req in todo:
                    found_week_2_3 += 1
                    break
    
        if found_week_2_3 < 4:
            errors.append(f"[X] Week 2-3 section should have 4 todos (code review, document, shadow, process improvement). Found {found_week_2_3}/4")
        else:
            checks_passed.append(f"[C] Week 2-3 section should have 4 todos (code review, document, shadow, process improvement). Found {found_week_2_3}/4")
    
        if not has_week_4_heading:
            errors.append("[X] Missing heading3 '📅 Week 4 Objectives'")
        else:
            checks_passed.append("[C] has heading3 '📅 Week 4 Objectives'")
    
        # 9. Validate Week 4 todos (3 required)
        required_week_4 = ["deploy", "present", "ownership"]
        found_week_4 = 0
        for req in required_week_4:
            for todo in week_4_todos:
                if req in todo:
                    found_week_4 += 1
                    break
    
        if found_week_4 < 3:
            errors.append(f"[X] Week 4 section should have 3 todos (deploy, present, ownership). Found {found_week_4}/3")
        else:
            checks_passed.append(f"[C] Week 4 section should have 3 todos (deploy, present, ownership). Found {found_week_4}/3")
    
        if not has_blue_callout:
            errors.append("[X] Missing callout with Blue background containing 'Pro tip'")
        else:
            checks_passed.append("[C] has callout with Blue background containing 'Pro tip'")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_agent_modify_project_guidelines_callouts(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Task: Modify callout blocks on 'Project Guidelines & Best Practices' page.
    
    Prompt: "On the 'Project Guidelines & Best Practices' page, which contains multiple callout blocks, 
    perform these precise modifications: First, find all callout blocks with Yellow background (💡 tips) 
    and add a paragraph immediately after each one with italic text saying 
    '*Implementation deadline: [30 days from today]*'. Then, locate all Red background callouts (🚨 critical) 
    and change their background color to Orange while keeping all other properties. Count the total number 
    of callout blocks on the page and add a new heading_2 at the very beginning of the page 
    (before any existing content) with text '📊 Guidelines Overview'. Under this heading, add a bulleted list 
    showing: '• Total guidelines: [total callout count]', '• Tips (yellow): [count]', 
    '• Warnings (orange): [count after color change]', '• Security notes (gray): [count]'."
    
    Validates:
    1. Find 'Project Guidelines & Best Practices' page
    2. Has heading2 '📊 Guidelines Overview' at very TOP
    3. Has bulletedList with accurate counts
    4. Each yellow callout (💡) is followed by italic paragraph with deadline
    5. NO red callouts remain (all converted to orange)
    6. Orange callouts retain 🚨 icon
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Find 'Project Guidelines & Best Practices' page using direct query
    try:
        guidelines_page = _find_page_by_title_direct(backend, "Project Guidelines & Best Practices")
        if not guidelines_page:
            errors.append("[X] Page 'Project Guidelines & Best Practices' not found")
        else:
            checks_passed.append("[C] Page 'Project Guidelines & Best Practices' found")
    
        page_id = guidelines_page.get("_id")
        if not page_id:
            errors.append("[X] Project Guidelines & Best Practices page has no _id")
        else:
            checks_passed.append("[C] Project Guidelines & Best Practices page has _id")
    
        # Get all blocks for the page using direct query
        blocks = _get_blocks_for_page_direct(backend, page_id)
        if not blocks:
            errors.append("[X] Page 'Project Guidelines & Best Practices' has no content blocks")
        else:
            checks_passed.append("[C] Page 'Project Guidelines & Best Practices' has content blocks")
    
        blocks.sort(key=lambda b: b.get("order", 0))
    
        # Count callouts by type
        total_callouts = 0
        yellow_callouts = []  # Track their orders
        orange_callouts = 0
        orange_callouts_with_warning_icon = 0  # Orange callouts that have 🚨 icon (converted from red)
        red_callouts = 0
        gray_callouts = 0
    
        for block in blocks:
            if block.get("type") == "callout":
                total_callouts += 1
                props = block.get("properties", {})
                bg_color = props.get("backgroundColor", "").lower()
                icon = props.get("icon", "")
            
                if "yellow" in bg_color:
                    yellow_callouts.append(block.get("order", 0))
                elif "orange" in bg_color:
                    orange_callouts += 1
                    # Check if this orange callout has the warning icon (converted from red, icon preserved)
                    if "🚨" in icon or "warning" in icon.lower():
                        orange_callouts_with_warning_icon += 1
                elif "red" in bg_color:
                    red_callouts += 1
                elif "gray" in bg_color or "grey" in bg_color:
                    gray_callouts += 1
    
        # 2. Check for overview heading at TOP
        has_overview_heading = False
        overview_order = None
        first_original_content_order = None
    
        for block in blocks:
            block_type = block.get("type", "")
            content = block.get("content", "")
            content_lower = content.lower()
            order = block.get("order", 0)
        
            if block_type == "heading2" and "guidelines overview" in content_lower:
                has_overview_heading = True
                overview_order = order
            elif block_type == "heading1" and "project guidelines" in content_lower and "overview" not in content_lower:
                # This is the original title heading
                if first_original_content_order is None:
                    first_original_content_order = order
    
        if not has_overview_heading:
            errors.append("[X] Missing heading2 '📊 Guidelines Overview' at the top")
        else:
            checks_passed.append("[C] has heading2 '📊 Guidelines Overview' at the top")
    
        if first_original_content_order is not None and overview_order is not None:
            if overview_order >= first_original_content_order:
                errors.append("[X] Guidelines Overview heading must appear BEFORE all original content")
            else:
                checks_passed.append("[C] Guidelines Overview heading must appear BEFORE all original content")
    
        # 3. Check for bulletedList with counts
        has_total_count = False
        has_tips_count = False
        has_warnings_count = False
        has_security_count = False
    
        for block in blocks:
            if block.get("type") in ["bulletedList", "bulletedListItem", "paragraph"]:
                content_lower = block.get("content", "").lower()
                if "total guidelines" in content_lower:
                    has_total_count = True
                if "tips" in content_lower and "yellow" in content_lower:
                    has_tips_count = True
                if "warnings" in content_lower and "orange" in content_lower:
                    has_warnings_count = True
                if "security" in content_lower and "gray" in content_lower:
                    has_security_count = True
    
        if not has_total_count:
            errors.append("[X] Missing bulletedList item '• Total guidelines: [count]'")
        else:
            checks_passed.append("[C] has bulletedList item '• Total guidelines: [count]'")
    
        if not has_tips_count:
            errors.append("[X] Missing bulletedList item '• Tips (yellow): [count]'")
        else:
            checks_passed.append("[C] has bulletedList item '• Tips (yellow): [count]'")
    
        if not has_warnings_count:
            errors.append("[X] Missing bulletedList item '• Warnings (orange): [count]'")
        else:
            checks_passed.append("[C] has bulletedList item '• Warnings (orange): [count]'")
    
        if not has_security_count:
            errors.append("[X] Missing bulletedList item '• Security notes (gray): [count]'")
        else:
            checks_passed.append("[C] has bulletedList item '• Security notes (gray): [count]'")
    
        # 4. Check that yellow callouts are followed by deadline paragraphs
        deadline_after_yellow = 0
        for yellow_order in yellow_callouts:
            # Find if there's a paragraph with "implementation deadline" right after
            for block in blocks:
                block_order = block.get("order", 0)
                # Look for blocks immediately after the yellow callout
                if block_order > yellow_order and block_order <= yellow_order + 2:
                    if block.get("type") == "paragraph":
                        content_lower = block.get("content", "").lower()
                        if "implementation deadline" in content_lower or "deadline" in content_lower:
                            deadline_after_yellow += 1
                            break
    
        if len(yellow_callouts) > 0 and deadline_after_yellow < len(yellow_callouts):
            errors.append(f"[X] Each yellow callout (💡) should be followed by deadline paragraph. Found {deadline_after_yellow}/{len(yellow_callouts)}")
        else:
            checks_passed.append(f"[C] Each yellow callout (💡) should be followed by deadline paragraph. Found {deadline_after_yellow}/{len(yellow_callouts)}")
    
        # 5. Verify NO red callouts remain
        if red_callouts > 0:
            errors.append(f"[X] Found {red_callouts} red callouts - all should be converted to orange")
        else:
            checks_passed.append(f"[C] Found {red_callouts} red callouts - all should be converted to orange")
    
        # 6. Verify converted orange callouts retained their warning icon (🚨)
        # There should be at least 1 orange callout with warning icon (originally red callouts)
        if orange_callouts > 0 and orange_callouts_with_warning_icon == 0:
            errors.append(f"[X] Orange callouts should retain 🚨 icon from original red callouts (found {orange_callouts} orange callouts but none with warning icon)")
        else:
            checks_passed.append(f"[C] Orange callouts should retain 🚨 icon from original red callouts (found {orange_callouts} orange callouts but none with warning icon)")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_agent_create_feature_tracking_system(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Task: Create an advanced tracking system in 'Feature Requests' page.
    
    Prompt: "In the 'Feature Requests' page, create an advanced tracking system. First, count the total 
    number of todo blocks. Add a heading_2 '🚀 Feature Implementation Tracker' immediately AFTER the 
    'Feature Requests' heading but BEFORE the first todo item. Under this, create a callout with 
    gradient styling (if not available, use Purple background) and '💡' icon. Inside the callout, add: 
    a bold heading 'Implementation Status', then a progress bar visualization using text 
    '▓▓▓▓░░░░░░ 30% Complete' (3 filled blocks for 30% based on 1 checked out of 3 todos + placeholder), 
    then three lines: 'Shipped Features: [X]', 'In Development: 0', 'Backlog: [Y]' where X is checked count 
    and Y is unchecked count. After the callout, add a heading_3 '🏷️ Feature Categories' with a bulleted 
    list categorizing features: 'UI/UX: [list features containing 'mode', 'shortcuts', or 'customization']', 
    'Export/Integration: [list features with 'export' or 'PDF']'."
    
    Validates:
    1. Find 'Feature Requests' page
    2. Has heading2 '🚀 Feature Implementation Tracker' after title but before todos
    3. Has callout with Purple background and '💡' icon
    4. Callout contains 'Implementation Status', progress bar, Shipped/In Development/Backlog counts
    5. Has heading3 '🏷️ Feature Categories'
    6. Has categorized bulletedList for UI/UX and Export/Integration
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Find 'Feature Requests' page using direct query
    try:
        feature_page = _find_page_by_title_direct(backend, "Feature Requests")
        if not feature_page:
            errors.append("[X] Page 'Feature Requests' not found")
        else:
            checks_passed.append("[C] Page 'Feature Requests' found")
    
        page_id = feature_page.get("_id")
        if not page_id:
            errors.append("[X] Feature Requests page has no _id")
        else:
            checks_passed.append("[C] Feature Requests page has _id")
    
        # Get all blocks for the page using direct query
        blocks = _get_blocks_for_page_direct(backend, page_id)
        if not blocks:
            errors.append("[X] Page 'Feature Requests' has no content blocks")
        else:
            checks_passed.append("[C] Page 'Feature Requests' has content blocks")
    
        blocks.sort(key=lambda b: b.get("order", 0))
    
        # Count todos
        todos = [b for b in blocks if b.get("type") == "todo"]
        checked_count = sum(1 for t in todos if t.get("properties", {}).get("checked", False))
        unchecked_count = len(todos) - checked_count
    
        # Find Feature Requests title heading
        title_order = None
        first_todo_order = None
    
        for block in blocks:
            block_type = block.get("type", "")
            content_lower = block.get("content", "").lower()
            order = block.get("order", 0)
        
            if block_type == "heading1" and "feature requests" in content_lower:
                title_order = order
            if block_type == "todo" and first_todo_order is None:
                first_todo_order = order
    
        # Validation flags
        has_tracker_heading = False
        tracker_order = None
        has_purple_callout = False
        has_implementation_status = False
        has_progress_bar = False
        has_shipped_count = False
        has_in_development_count = False
        has_backlog_count = False
        has_categories_heading = False
        has_ui_ux_category = False
        has_export_category = False
    
        for block in blocks:
            block_type = block.get("type", "")
            content = block.get("content", "")
            content_lower = content.lower()
            props = block.get("properties", {})
            order = block.get("order", 0)
        
            # 2. Check for tracker heading
            if block_type == "heading2" and "feature implementation tracker" in content_lower:
                has_tracker_heading = True
                tracker_order = order
                # Verify positioning
                if title_order is not None and order <= title_order:
                    errors.append("[X] Tracker heading must appear AFTER Feature Requests title")
                else:
                    checks_passed.append("[C] Tracker heading must appear AFTER Feature Requests title")
                if first_todo_order is not None and order >= first_todo_order:
                    errors.append("[X] Tracker heading must appear BEFORE first todo item")
                else:
                    checks_passed.append("[C] Tracker heading must appear BEFORE first todo item")
        
            # 3. Check for purple callout
            if block_type == "callout":
                bg_color = props.get("backgroundColor", "").lower()
                icon = props.get("icon", "")
                if "purple" in bg_color or "gradient" in bg_color:
                    if "💡" in icon or "💡" in content:
                        has_purple_callout = True
                    
                        # 4. Check callout content
                        if "implementation status" in content_lower:
                            has_implementation_status = True
                        if "▓" in content or "░" in content or "%" in content_lower:
                            has_progress_bar = True
                        if "shipped" in content_lower:
                            has_shipped_count = True
                        if "in development" in content_lower:
                            has_in_development_count = True
                        if "backlog" in content_lower:
                            has_backlog_count = True
        
            # 5. Check for categories heading
            if block_type == "heading3" and "feature categories" in content_lower:
                has_categories_heading = True
        
            # 6. Check for category lists
            if block_type in ["bulletedList", "bulletedListItem", "paragraph"]:
                if "ui/ux" in content_lower or "ui / ux" in content_lower:
                    # Check for UI features
                    if any(kw in content_lower for kw in ["mode", "shortcuts", "customization", "dark"]):
                        has_ui_ux_category = True
                if "export" in content_lower or "integration" in content_lower:
                    if "pdf" in content_lower or "export" in content_lower:
                        has_export_category = True
    
        # Validate all checks
        if not has_tracker_heading:
            errors.append("[X] Missing heading2 '🚀 Feature Implementation Tracker'")
        else:
            checks_passed.append("[C] has heading2 '🚀 Feature Implementation Tracker'")
    
        if not has_purple_callout:
            errors.append("[X] Missing callout with Purple background and '💡' icon")
        else:
            checks_passed.append("[C] has callout with Purple background and '💡' icon")
    
        if not has_implementation_status:
            errors.append("[X] Callout missing 'Implementation Status' text")
        else:
            checks_passed.append("[C] Callout has 'Implementation Status' text")
    
        if not has_progress_bar:
            errors.append("[X] Callout missing progress bar visualization")
        else:
            checks_passed.append("[C] Callout has progress bar visualization")
    
        if not has_shipped_count:
            errors.append("[X] Callout missing 'Shipped Features' count")
        else:
            checks_passed.append("[C] Callout has 'Shipped Features' count")
    
        if not has_in_development_count:
            errors.append("[X] Callout missing 'In Development' count")
        else:
            checks_passed.append("[C] Callout has 'In Development' count")
    
        if not has_backlog_count:
            errors.append("[X] Callout missing 'Backlog' count")
        else:
            checks_passed.append("[C] Callout has 'Backlog' count")
    
        if not has_categories_heading:
            errors.append("[X] Missing heading3 '🏷️ Feature Categories'")
        else:
            checks_passed.append("[C] has heading3 '🏷️ Feature Categories'")
    
        if not has_ui_ux_category:
            errors.append("[X] Missing UI/UX category with dark mode/shortcuts features")
        else:
            checks_passed.append("[C] has UI/UX category with dark mode/shortcuts features")
    
        if not has_export_category:
            errors.append("[X] Missing Export/Integration category with PDF export feature")
        else:
            checks_passed.append("[C] has Export/Integration category with PDF export feature")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_agent_swap_prd_sections(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Task: Swap Overview and User Stories sections in 'Comprehensive Product Requirements Document'.
    
    Prompt: "Navigate to the 'Comprehensive Product Requirements Document' page. First, swap the positions 
    of the 'Overview' section (including all its Part 1, 2, 3 subsections) with the 'User Stories' section 
    (including all its subsections), preserving all content and structure. Then, at the very beginning of 
    the newly positioned 'User Stories' section (which is now first), insert a callout with green background 
    and '🎯' icon containing a heading_3 'Priority Stories' and a numbered list: 
    '1. Mobile responsiveness implementation', '2. Real-time collaboration features', 
    '3. Advanced search functionality'. Finally, add a new heading_2 '📊 Requirements Summary' at the end 
    of the document with a paragraph: 'Total sections: 8 | Total requirements: 96 | Priority items: 3'."
    
    Validates:
    1. Find 'Comprehensive Product Requirements Document' page
    2. 'User Stories' heading2 appears BEFORE 'Overview' heading2
    3. User Stories subsections remain intact
    4. Overview subsections remain intact
    5. Green callout with '🎯' icon at start of User Stories
    6. Callout contains 'Priority Stories' heading3 and 3 numbered items
    7. Has heading2 '📊 Requirements Summary' at END
    8. Summary paragraph with counts
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Find 'Comprehensive Product Requirements Document' page
    try:
        prd_page = _find_page_by_title(final_state_backend, "Comprehensive Product Requirements Document")
        if not prd_page:
            errors.append("[X] Page 'Comprehensive Product Requirements Document' not found")
        else:
            checks_passed.append("[C] Page 'Comprehensive Product Requirements Document' found")
    
        page_id = prd_page.get("_id")
        if not page_id:
            errors.append("[X] Comprehensive Product Requirements Document page has no _id")
        else:
            checks_passed.append("[C] Comprehensive Product Requirements Document page has _id")
    
        # Get all blocks for the page
        blocks = _get_blocks_for_page(final_state_backend, page_id)
        if not blocks:
            errors.append("[X] Page 'Comprehensive Product Requirements Document' has no content blocks")
        else:
            checks_passed.append("[C] Page 'Comprehensive Product Requirements Document' has content blocks")
    
        blocks.sort(key=lambda b: b.get("order", 0))
    
        # Find Overview and User Stories heading orders
        overview_order = None
        user_stories_order = None
    
        for block in blocks:
            if block.get("type") == "heading2":
                content_lower = block.get("content", "").lower()
                if content_lower == "overview" or "overview" == content_lower.strip():
                    overview_order = block.get("order", 0)
                elif "user stories" in content_lower:
                    user_stories_order = block.get("order", 0)
    
        # 2. Verify User Stories comes BEFORE Overview (sections swapped)
        if user_stories_order is None:
            errors.append("[X] Heading 'User Stories' not found")
        else:
            checks_passed.append("[C] Heading 'User Stories' found")
    
        if overview_order is None:
            errors.append("[X] Heading 'Overview' not found")
        else:
            checks_passed.append("[C] Heading 'Overview' found")
    
        if user_stories_order >= overview_order:
            errors.append(f"[X] Sections not swapped: User Stories (order {user_stories_order}) should come BEFORE Overview (order {overview_order})")
        else:
            checks_passed.append(f"[C] Sections swapped: User Stories (order {user_stories_order}) should come BEFORE Overview (order {overview_order})")
    
        # 3-4. Check for subsections (Part 1, 2, 3) under each section
        user_stories_parts = 0
        overview_parts = 0
        current_section = None
    
        for block in blocks:
            if block.get("type") == "heading2":
                content_lower = block.get("content", "").lower()
                if "user stories" in content_lower:
                    current_section = "user_stories"
                elif content_lower == "overview" or "overview" == content_lower.strip():
                    current_section = "overview"
                else:
                    current_section = None
            elif block.get("type") == "heading3":
                content_lower = block.get("content", "").lower()
                if "part" in content_lower:
                    if current_section == "user_stories":
                        user_stories_parts += 1
                    elif current_section == "overview":
                        overview_parts += 1
    
        if user_stories_parts < 3:
            errors.append(f"[X] User Stories section should have 3 subsections (Part 1, 2, 3), found {user_stories_parts}")
        else:
            checks_passed.append(f"[C] User Stories section should have 3 subsections (Part 1, 2, 3), found {user_stories_parts}")
    
        if overview_parts < 3:
            errors.append(f"[X] Overview section should have 3 subsections (Part 1, 2, 3), found {overview_parts}")
        else:
            checks_passed.append(f"[C] Overview section should have 3 subsections (Part 1, 2, 3), found {overview_parts}")
    
        # 5-6. Check for green callout with Priority Stories
        has_green_callout = False
        has_priority_stories = False
        has_priority_items = False
    
        for block in blocks:
            if block.get("type") == "callout":
                props = block.get("properties", {})
                bg_color = props.get("backgroundColor", "").lower()
                icon = props.get("icon", "")
                content = block.get("content", "")
                content_lower = content.lower()
            
                if "green" in bg_color and ("🎯" in icon or "🎯" in content):
                    has_green_callout = True
                
                    if "priority stories" in content_lower:
                        has_priority_stories = True
                
                    # Check for the 3 priority items
                    if all(item in content_lower for item in ["mobile", "real-time", "search"]):
                        has_priority_items = True
                    elif "1." in content and "2." in content and "3." in content:
                        has_priority_items = True
    
        if not has_green_callout:
            errors.append("[X] Missing green callout with '🎯' icon at start of User Stories section")
        else:
            checks_passed.append("[C] has green callout with '🎯' icon at start of User Stories section")
    
        if not has_priority_stories:
            errors.append("[X] Green callout missing 'Priority Stories' heading")
        else:
            checks_passed.append("[C] Green callout has 'Priority Stories' heading")
    
        if not has_priority_items:
            errors.append("[X] Green callout missing 3 priority items (mobile, real-time collaboration, search)")
        else:
            checks_passed.append("[C] Green callout has 3 priority items (mobile, real-time collaboration, search)")
    
        # 7-8. Check for Requirements Summary at end
        has_summary_heading = False
        has_summary_paragraph = False
        max_order = max(b.get("order", 0) for b in blocks)
    
        for block in blocks:
            block_type = block.get("type", "")
            content = block.get("content", "")
            content_lower = content.lower()
            order = block.get("order", 0)
        
            if block_type == "heading2" and "requirements summary" in content_lower:
                has_summary_heading = True
                # Verify it's near the end
                if order < max_order - 5:
                    errors.append("[X] Requirements Summary heading should be at the END of the document")
                else:
                    checks_passed.append("[C] Requirements Summary heading should be at the END of the document")
        
            if block_type == "paragraph" and "total sections" in content_lower:
                if "total requirements" in content_lower or "priority items" in content_lower:
                    has_summary_paragraph = True
    
        if not has_summary_heading:
            errors.append("[X] Missing heading2 '📊 Requirements Summary' at end of document")
        else:
            checks_passed.append("[C] has heading2 '📊 Requirements Summary' at end of document")
    
        if not has_summary_paragraph:
            errors.append("[X] Missing summary paragraph with section/requirements/priority counts")
        else:
            checks_passed.append("[C] has summary paragraph with section/requirements/priority counts")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_agent_add_sprint_goals_alignment_section(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Task: In the 'Weekly Standup Template' page, locate the 'What I plan to do next week' section.
    Add a new section immediately AFTER this section but BEFORE the 'Blockers' heading.
    Title it with heading2 '🎯 Sprint Goals Alignment'. Under this heading, add a numbered list
    with exactly these items: '1. Review sprint backlog for priority changes',
    '2. Align tasks with quarterly OKRs', '3. Identify dependencies with other teams'.
    Then, in the existing 'Blockers' section, change the color of any unchecked to-do items to red.
    Finally, at the very beginning of the page (after the main title but before any other content),
    insert a quote block with the exact text: 'Focus on outcomes, not outputs. - Product Team Mantra'.
    
    Validates:
    1. 'Weekly Standup Template' page exists
    2. Quote block with exact text appears after heading1 but before other content
    3. heading2 '🎯 Sprint Goals Alignment' exists
    4. Section is positioned AFTER 'What I plan to do next week' but BEFORE 'Blockers'
    5. Numbered list with exact 3 items exists under the section heading
    6. Unchecked todos in 'Blockers' section have red color property
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Find Weekly Standup Template page
    try:
        weekly_standup = _find_page_by_title(final_state_backend, "Weekly Standup Template")
        if not weekly_standup:
            errors.append("[X] Weekly Standup Template page not found")
        else:
            checks_passed.append("[C] Weekly Standup Template page found")
    
        weekly_standup_id = weekly_standup.get("_id")
    
        # Get all blocks for this page, sorted by order
        page_blocks = _get_blocks_for_page(final_state_backend, weekly_standup_id)
        sorted_blocks = sorted(page_blocks, key=lambda x: x.get("order", 0))
    
        if not sorted_blocks:
            errors.append("[X] No blocks found on Weekly Standup Template page")
        else:
            checks_passed.append("[C] blocks found on Weekly Standup Template page")
    
        # Find key section indices
        heading1_idx = None
        next_week_heading_idx = None
        blockers_heading_idx = None
        sprint_goals_heading_idx = None
        quote_idx = None
    
        for i, block in enumerate(sorted_blocks):
            content = block.get("content", "")
            content_lower = content.lower()
            block_type = block.get("type", "").lower()
        
            if block_type == "heading1":
                heading1_idx = i
        
            if block_type == "quote" and "focus on outcomes, not outputs" in content_lower and "product team mantra" in content_lower:
                quote_idx = i
        
            if block_type == "heading2":
                if "what i plan to do next week" in content_lower:
                    next_week_heading_idx = i
                elif "blockers" in content_lower:
                    blockers_heading_idx = i
                elif "sprint goals alignment" in content_lower and "🎯" in content:
                    sprint_goals_heading_idx = i
    
        # 2. Validate quote block position
        if quote_idx is None:
            errors.append("[X] Quote block with 'Focus on outcomes, not outputs. - Product Team Mantra' not found")
        else:
            checks_passed.append("[C] Quote block with 'Focus on outcomes, outputs. - Product Team Mantra' found")
    
        if heading1_idx is None:
            errors.append("[X] No heading1 found on page")
        else:
            checks_passed.append("[C] heading1 found on page")
    
        # Quote should be right after heading1 (within first few blocks)
        if quote_idx <= heading1_idx:
            errors.append("[X] Quote block should appear AFTER the main title (heading1)")
        else:
            checks_passed.append("[C] Quote block should appear AFTER the main title (heading1)")
    
        # Check quote appears before other significant content (next_week or blockers sections)
        if next_week_heading_idx is not None and quote_idx > next_week_heading_idx:
            errors.append("[X] Quote block should appear at the beginning of the page, before 'What I plan to do next week' section")
        else:
            checks_passed.append("[C] Quote block should appear at the beginning of the page, before 'What I plan to do next week' section")
    
        # 3. Validate Sprint Goals Alignment heading exists
        if sprint_goals_heading_idx is None:
            errors.append("[X] heading2 '🎯 Sprint Goals Alignment' not found")
        else:
            checks_passed.append("[C] heading2 '🎯 Sprint Goals Alignment' found")
    
        # 4. Validate position: after 'What I plan to do next week' but before 'Blockers'
        if next_week_heading_idx is None:
            errors.append("[X] Could not find 'What I plan to do next week' heading")
        else:
            checks_passed.append("[C] Could find 'What I plan to do next week' heading")
    
        if blockers_heading_idx is None:
            errors.append("[X] Could not find 'Blockers' heading")
        else:
            checks_passed.append("[C] Could find 'Blockers' heading")
    
        if not (next_week_heading_idx < sprint_goals_heading_idx < blockers_heading_idx):
            errors.append(f"[X] '🎯 Sprint Goals Alignment' section must be positioned AFTER 'What I plan to do next week' but BEFORE 'Blockers'. Found at index {sprint_goals_heading_idx}, next_week at {next_week_heading_idx}, blockers at {blockers_heading_idx}")
        else:
            checks_passed.append(f"[C] '🎯 Sprint Goals Alignment' section must be positioned AFTER 'What I plan to do next week' but BEFORE 'Blockers'. Found at index {sprint_goals_heading_idx}, next_week at {next_week_heading_idx}, blockers at {blockers_heading_idx}")
    
        # 5. Validate numbered list with exact 3 items after Sprint Goals Alignment heading
        expected_items = [
            "review sprint backlog for priority changes",
            "align tasks with quarterly okrs",
            "identify dependencies with other teams"
        ]
    
        found_items = []
        for i in range(sprint_goals_heading_idx + 1, blockers_heading_idx):
            block = sorted_blocks[i]
            block_type = block.get("type", "").lower()
            content = block.get("content", "")
            content_lower = content.lower()
        
            if block_type in ["numberedlist", "numbered_list"]:
                for expected in expected_items:
                    if expected in content_lower and expected not in found_items:
                        found_items.append(expected)
    
        if len(found_items) < 3:
            missing = [item for item in expected_items if item not in found_items]
            errors.append(f"[X] Missing numbered list items in Sprint Goals Alignment section: {missing}")
        else:
            checks_passed.append(f"[C] has numbered list items in Sprint Goals Alignment section: {has}")
    
        # 6. Validate unchecked todos in Blockers section have red color
        unchecked_todos_in_blockers = []
        for i in range(blockers_heading_idx + 1, len(sorted_blocks)):
            block = sorted_blocks[i]
            block_type = block.get("type", "").lower()
        
            # Stop if we hit another heading (end of Blockers section)
            if block_type in ["heading1", "heading2", "heading3"]:
                break
        
            if block_type == "todo":
                is_checked = block.get("properties", {}).get("checked", False)
                if not is_checked:
                    unchecked_todos_in_blockers.append(block)
    
        if not unchecked_todos_in_blockers:
            errors.append("[X] No unchecked todos found in Blockers section")
        else:
            checks_passed.append("[C] unchecked todos found in Blockers section")
    
        # Check all unchecked todos have red color
        for todo in unchecked_todos_in_blockers:
            props = todo.get("properties", {})
            color = props.get("color", "")
            if color.lower() != "red":
                errors.append(f"[X] Unchecked todo in Blockers section does not have red color. Found color: '{color}'")
            else:
                checks_passed.append(f"[C] Unchecked todo in Blockers section has red color. Found color: '{color}'")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_agent_add_quarterly_milestones_section(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Task: In the 'Project Roadmap' page, add a new section immediately AFTER the quote block but
    BEFORE the 'Strategic Priorities' heading. Title it heading2 '🎯 Quarterly Milestones'.
    Fetch Q1 Goals and Q2 Goals sub-pages, count their completed vs total todos. Create a numbered
    list: '1. Q1 2024: [X] of [Y] objectives completed ([Z]%)', '2. Q2 2024: [A] of [B] objectives
    completed ([C]%)'. Then in Strategic Priorities section, after each bullet point, add status
    in parentheses: check if related objectives exist in Q1/Q2 pages - '(🟢 On track)' if mentioned,
    '(🔴 Not started)' if not found. Finally, add a divider after all content, then a callout with
    blue background and 📈 icon: 'Overall roadmap completion: [TOTAL]%'.
    
    Validates:
    1. 'Project Roadmap' page exists
    2. heading2 '🎯 Quarterly Milestones' exists after quote but before Strategic Priorities
    3. Numbered list with accurate Q1 stats (2 of 3 = 67%)
    4. Numbered list with accurate Q2 stats (0 of 2 = 0%)
    5. Strategic Priorities bullets have status indicators based on substring matching
    6. Divider exists after all content
    7. Blue callout with 📈 icon and overall percentage
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Find Project Roadmap page using direct query
    try:
        roadmap_page = _find_page_by_title_direct(backend, "Project Roadmap")
        if not roadmap_page:
            errors.append("[X] Project Roadmap page not found")
        else:
            checks_passed.append("[C] Project Roadmap page found")
    
        roadmap_id = roadmap_page.get("_id")
    
        # Find Q1 Goals and Q2 Goals sub-pages using direct query
        q1_page = _find_page_by_title_direct(backend, "Q1 Goals")
        q2_page = _find_page_by_title_direct(backend, "Q2 Goals")
    
        if not q1_page:
            errors.append("[X] Q1 Goals page not found")
        else:
            checks_passed.append("[C] Q1 Goals page found")
        if not q2_page:
            errors.append("[X] Q2 Goals page not found")
        else:
            checks_passed.append("[C] Q2 Goals page found")
    
        # Count todos in Q1 and Q2 pages using direct query
        q1_blocks = _get_blocks_for_page_direct(backend, q1_page.get("_id"))
        q2_blocks = _get_blocks_for_page_direct(backend, q2_page.get("_id"))
    
        q1_todos = [b for b in q1_blocks if b.get("type") == "todo"]
        q2_todos = [b for b in q2_blocks if b.get("type") == "todo"]
    
        q1_checked = sum(1 for t in q1_todos if t.get("properties", {}).get("checked", False))
        q2_checked = sum(1 for t in q2_todos if t.get("properties", {}).get("checked", False))
    
        q1_total = len(q1_todos)
        q2_total = len(q2_todos)
    
        q1_percent = int((q1_checked / q1_total * 100)) if q1_total > 0 else 0
        q2_percent = int((q2_checked / q2_total * 100)) if q2_total > 0 else 0
    
        # Get combined Q1/Q2 todo content for status matching
        q1_q2_content = " ".join([b.get("content", "").lower() for b in q1_todos + q2_todos])
    
        # Get all blocks for roadmap page using direct query, sorted by order
        page_blocks = _get_blocks_for_page_direct(backend, roadmap_id)
        sorted_blocks = sorted(page_blocks, key=lambda x: x.get("order", 0))
    
        if not sorted_blocks:
            errors.append("[X] No blocks found on Project Roadmap page")
        else:
            checks_passed.append("[C] blocks found on Project Roadmap page")
    
        # Find key indices
        quote_idx = None
        strategic_priorities_idx = None
        quarterly_milestones_idx = None
    
        for i, block in enumerate(sorted_blocks):
            content = block.get("content", "")
            content_lower = content.lower()
            block_type = block.get("type", "").lower()
        
            if block_type == "quote":
                quote_idx = i
        
            if block_type == "heading2":
                if "strategic priorities" in content_lower:
                    strategic_priorities_idx = i
                elif "quarterly milestones" in content_lower and "🎯" in content:
                    quarterly_milestones_idx = i
    
        # 2. Validate Quarterly Milestones heading position
        if quarterly_milestones_idx is None:
            errors.append("[X] heading2 '🎯 Quarterly Milestones' not found")
        else:
            checks_passed.append("[C] heading2 '🎯 Quarterly Milestones' found")
    
        if quote_idx is None:
            errors.append("[X] Quote block not found on Project Roadmap page")
        else:
            checks_passed.append("[C] Quote block found on Project Roadmap page")
    
        if strategic_priorities_idx is None:
            errors.append("[X] heading2 'Strategic Priorities' not found")
        else:
            checks_passed.append("[C] heading2 'Strategic Priorities' found")
    
        if not (quote_idx < quarterly_milestones_idx < strategic_priorities_idx):
            errors.append(f"[X] '🎯 Quarterly Milestones' must be positioned AFTER quote but BEFORE 'Strategic Priorities'. Quote at {quote_idx}, milestones at {quarterly_milestones_idx}, priorities at {strategic_priorities_idx}")
        else:
            checks_passed.append(f"[C] '🎯 Quarterly Milestones' must be positioned AFTER quote but BEFORE 'Strategic Priorities'. Quote at {quote_idx}, milestones at {quarterly_milestones_idx}, priorities at {strategic_priorities_idx}")
    
        # 3 & 4. Validate numbered list with Q1 and Q2 stats
        found_q1_stats = False
        found_q2_stats = False
    
        for i in range(quarterly_milestones_idx + 1, strategic_priorities_idx):
            block = sorted_blocks[i]
            block_type = block.get("type", "").lower()
            content = block.get("content", "")
            content_lower = content.lower()
        
            if block_type in ["numberedlist", "numbered_list"]:
                # Check for Q1 stats
                if "q1" in content_lower and "2024" in content_lower:
                    # Validate numbers - check for completed/total format
                    if str(q1_checked) in content and str(q1_total) in content:
                        found_q1_stats = True
            
                # Check for Q2 stats
                if "q2" in content_lower and "2024" in content_lower:
                    if str(q2_checked) in content and str(q2_total) in content:
                        found_q2_stats = True
    
        if not found_q1_stats:
            errors.append(f"[X] Missing or incorrect Q1 2024 stats in numbered list. Expected: {q1_checked} of {q1_total} ({q1_percent}%)")
        else:
            checks_passed.append(f"[C] has or incorrect Q1 2024 stats in numbered list. Expected: {q1_checked} of {q1_total} ({q1_percent}%)")
    
        if not found_q2_stats:
            errors.append(f"[X] Missing or incorrect Q2 2024 stats in numbered list. Expected: {q2_checked} of {q2_total} ({q2_percent}%)")
        else:
            checks_passed.append(f"[C] has or incorrect Q2 2024 stats in numbered list. Expected: {q2_checked} of {q2_total} ({q2_percent}%)")
    
        # 5. Validate Strategic Priorities have status indicators
        priorities_with_status = 0
        priorities_count = 0
    
        for i in range(strategic_priorities_idx + 1, len(sorted_blocks)):
            block = sorted_blocks[i]
            block_type = block.get("type", "").lower()
            content = block.get("content", "")
        
            # Stop at next heading
            if block_type in ["heading1", "heading2", "heading3"]:
                break
        
            if block_type in ["bulletedlist", "bulleted_list"]:
                priorities_count += 1
                # Check for status indicator
                if "🟢" in content or "🔴" in content:
                    priorities_with_status += 1
    
        if priorities_count == 0:
            errors.append("[X] No bullet points found in Strategic Priorities section")
        else:
            checks_passed.append("[C] bullet points found in Strategic Priorities section")
    
        if priorities_with_status < priorities_count:
            errors.append(f"[X] Not all Strategic Priorities bullets have status indicators. Found {priorities_with_status} of {priorities_count} with indicators")
        else:
            checks_passed.append(f"[C] all Strategic Priorities bullets have status indicators. Found {priorities_with_status} of {priorities_count} with indicators")
    
        # 6 & 7. Validate divider and blue callout at end
        found_divider = False
        found_blue_callout = False
        overall_percent = int((q1_checked + q2_checked) / (q1_total + q2_total) * 100) if (q1_total + q2_total) > 0 else 0
    
        # Look for divider and callout near end of document
        for block in sorted_blocks[-10:]:  # Check last 10 blocks
            block_type = block.get("type", "").lower()
            content = block.get("content", "")
            props = block.get("properties", {})
        
            if block_type == "divider":
                found_divider = True
        
            if block_type == "callout":
                bg_color = props.get("backgroundColor", "")
                icon = props.get("icon", "")
                if "blue" in bg_color.lower() and "📈" in icon:
                    if "overall" in content.lower() and "roadmap" in content.lower() and "completion" in content.lower():
                        found_blue_callout = True
    
        if not found_divider:
            errors.append("[X] Divider not found after content")
        else:
            checks_passed.append("[C] Divider found after content")
    
        if not found_blue_callout:
            errors.append("[X] Blue callout with 📈 icon and overall roadmap completion percentage not found")
        else:
            checks_passed.append("[C] Blue callout with 📈 icon and overall roadmap completion percentage found")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_agent_create_feature_request_pipeline(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Task: In the 'Feature Requests' page, add a comprehensive tracking system at the top of the page.
    Insert heading1 '✨ Feature Request Tracker' if no heading1 exists, otherwise insert immediately
    after it. Add heading2 '📊 Request Pipeline' followed by four sequential callout blocks representing
    pipeline stages: 1) Red background with 🔴 icon titled 'New Requests' containing
    '• Authentication improvements • Dark mode support', 2) Yellow background with 🟡 icon titled
    'Under Review' containing '• API rate limiting • Export functionality', 3) Blue background with
    🔵 icon titled 'In Development' containing '• Mobile app optimization', 4) Green background with
    🟢 icon titled 'Completed' containing '• Search functionality v2 • Notification system'. After
    all callouts, add a code block with language 'markdown' containing:
    '## Monthly Summary - New: 2 - Reviewed: 2 - Developing: 1 - Completed: 2'.
    
    Validates:
    1. 'Feature Requests' page exists
    2. heading1 '✨ Feature Request Tracker' exists or tracker content follows existing heading1
    3. heading2 '📊 Request Pipeline' exists
    4. Four callouts in correct sequence with exact colors, icons, titles, and content
    5. Code block with language='markdown' and exact summary format
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Find Feature Requests page using direct query
    try:
        feature_page = _find_page_by_title_direct(backend, "Feature Requests")
        if not feature_page:
            errors.append("[X] Feature Requests page not found")
        else:
            checks_passed.append("[C] Feature Requests page found")
    
        feature_page_id = feature_page.get("_id")
    
        # Get all blocks for this page using direct query, sorted by order
        page_blocks = _get_blocks_for_page_direct(backend, feature_page_id)
        sorted_blocks = sorted(page_blocks, key=lambda x: x.get("order", 0))
    
        if not sorted_blocks:
            errors.append("[X] No blocks found on Feature Requests page")
        else:
            checks_passed.append("[C] blocks found on Feature Requests page")
    
        # 2. Find heading1 with tracker or original heading
        tracker_heading_idx = None
        pipeline_heading_idx = None
    
        for i, block in enumerate(sorted_blocks):
            content = block.get("content", "")
            content_lower = content.lower()
            block_type = block.get("type", "").lower()
        
            if block_type == "heading1" and "feature request tracker" in content_lower and "✨" in content:
                tracker_heading_idx = i
        
            if block_type == "heading2" and "request pipeline" in content_lower and "📊" in content:
                pipeline_heading_idx = i
    
        # 3. Validate pipeline heading exists
        if pipeline_heading_idx is None:
            errors.append("[X] heading2 '📊 Request Pipeline' not found")
        else:
            checks_passed.append("[C] heading2 '📊 Request Pipeline' found")
    
        # 4. Validate four callouts in correct sequence
        expected_callouts = [
            {
                "color": "red",
                "icon": "🔴",
                "title": "new requests",
                "content_items": ["authentication improvements", "dark mode support"]
            },
            {
                "color": "yellow",
                "icon": "🟡",
                "title": "under review",
                "content_items": ["api rate limiting", "export functionality"]
            },
            {
                "color": "blue",
                "icon": "🔵",
                "title": "in development",
                "content_items": ["mobile app optimization"]
            },
            {
                "color": "green",
                "icon": "🟢",
                "title": "completed",
                "content_items": ["search functionality v2", "notification system"]
            }
        ]
    
        # Find callouts after pipeline heading
        callouts_found = []
        code_block_found = False
        code_block_valid = False
    
        for i in range(pipeline_heading_idx + 1, len(sorted_blocks)):
            block = sorted_blocks[i]
            block_type = block.get("type", "").lower()
            content = block.get("content", "")
            content_lower = content.lower()
            props = block.get("properties", {})
        
            if block_type == "callout":
                bg_color = props.get("backgroundColor", "").lower()
                icon = props.get("icon", "")
                callouts_found.append({
                    "bg_color": bg_color,
                    "icon": icon,
                    "content": content_lower
                })
        
            if block_type == "code":
                code_block_found = True
                language = props.get("language", "").lower()
                if language == "markdown":
                    # Check for summary content
                    if "monthly summary" in content_lower:
                        if "new: 2" in content_lower and "reviewed: 2" in content_lower:
                            if "developing: 1" in content_lower and "completed: 2" in content_lower:
                                code_block_valid = True
    
        if len(callouts_found) < 4:
            errors.append(f"[X] Expected 4 pipeline callouts, found {len(callouts_found)}")
        else:
            checks_passed.append(f"[C] Found 4 pipeline callouts as expected")
    
        # Validate each callout in sequence
        for idx, expected in enumerate(expected_callouts):
            if idx >= len(callouts_found):
                errors.append(f"[X] Missing callout #{idx + 1}: {expected['title']}")
            else:
                checks_passed.append(f"[C] has callout #{idx + 1}: {expected['title']}")
        
            actual = callouts_found[idx]
        
            # Check color
            if expected["color"] not in actual["bg_color"]:
                errors.append(f"[X] Callout #{idx + 1} should have {expected['color']} background, found: {actual['bg_color']}")
            else:
                checks_passed.append(f"[C] Callout #{idx + 1} should have {expected['color']} background, found: {actual['bg_color']}")
        
            # Check icon
            if expected["icon"] not in actual["icon"]:
                errors.append(f"[X] Callout #{idx + 1} should have {expected['icon']} icon, found: {actual['icon']}")
            else:
                checks_passed.append(f"[C] Callout #{idx + 1} should have {expected['icon']} icon, found: {actual['icon']}")
        
            # Check title
            if expected["title"] not in actual["content"]:
                errors.append(f"[X] Callout #{idx + 1} should contain title '{expected['title']}' in content")
            else:
                checks_passed.append(f"[C] Callout #{idx + 1} should contain title '{expected['title']}' in content")
        
            # Check content items
            for item in expected["content_items"]:
                if item not in actual["content"]:
                    errors.append(f"[X] Callout #{idx + 1} missing content item: '{item}'")
                else:
                    checks_passed.append(f"[C] Callout #{idx + 1} has content item: '{item}'")
    
        # 5. Validate code block
        if not code_block_found:
            errors.append("[X] Code block not found after pipeline callouts")
        else:
            checks_passed.append("[C] Code block found after pipeline callouts")
    
        if not code_block_valid:
            errors.append("[X] Code block missing: language='markdown' and/or correct Monthly Summary format (New: 2 - Reviewed: 2 - Developing: 1 - Completed: 2)")
        else:
            checks_passed.append("[C] Code block has: language='markdown' and/or correct Monthly Summary format (New: 2 - Reviewed: 2 - Developing: 1 - Completed: 2)")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_agent_add_guidelines_review_todos(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Task: On the 'Project Guidelines & Best Practices' page, find all callout blocks with
    yellow_background (💡 tips). For each one found, add a new to-do block immediately after it
    with unchecked status and text '📝 Review and apply: [first 30 characters of the callout text]...'.
    Then, at the very beginning of the page after the heading_1, add a new callout with gray_background
    and 📊 icon containing: a bold paragraph 'Quick Stats' followed by a bulleted list with
    '• Total Guidelines: [count of all callouts]', '• Tips to Review: [count of yellow callouts]',
    '• Critical Warnings: [count of red callouts]'. Finally, add a divider at the end of the page.
    
    Validates:
    1. 'Project Guidelines & Best Practices' page exists
    2. Gray callout with 📊 icon exists after heading_1
    3. Gray callout contains 'Quick Stats' (bold)
    4. Gray callout has correct counts for total, yellow, and red callouts
    5. Each yellow_background callout is followed by unchecked todo with correct format
    6. Divider exists at end of page
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Find Project Guidelines & Best Practices page
    try:
        guidelines_page = _find_page_by_title(final_state_backend, "Project Guidelines & Best Practices")
        if not guidelines_page:
            errors.append("[X] Project Guidelines & Best Practices page not found")
        else:
            checks_passed.append("[C] Project Guidelines & Best Practices page found")
    
        guidelines_page_id = guidelines_page.get("_id")
    
        # Get all blocks for this page, sorted by order
        page_blocks = _get_blocks_for_page(final_state_backend, guidelines_page_id)
        sorted_blocks = sorted(page_blocks, key=lambda x: x.get("order", 0))
    
        if not sorted_blocks:
            errors.append("[X] No blocks found on Project Guidelines & Best Practices page")
        else:
            checks_passed.append("[C] blocks found on Project Guidelines & Best Practices page")
    
        # Count callouts by type (from original state: yellow, red, etc.)
        # We need to count all callouts, yellow callouts, and red callouts
        total_callouts = 0
        yellow_callouts = 0
        red_callouts = 0
        yellow_callout_indices = []
    
        heading1_idx = None
        stats_callout_idx = None
    
        for i, block in enumerate(sorted_blocks):
            block_type = block.get("type", "").lower()
            content = block.get("content", "")
            props = block.get("properties", {})
        
            if block_type == "heading1":
                heading1_idx = i
        
            if block_type == "callout":
                bg_color = props.get("backgroundColor", "").lower()
                icon = props.get("icon", "")
            
                # Check if this is the stats callout (gray with 📊)
                if "gray" in bg_color and "📊" in icon:
                    stats_callout_idx = i
                    continue  # Don't count the stats callout itself
            
                total_callouts += 1
            
                if "yellow" in bg_color:
                    yellow_callouts += 1
                    yellow_callout_indices.append(i)
            
                if "red" in bg_color:
                    red_callouts += 1
    
        # 2. Validate gray stats callout exists after heading_1
        if stats_callout_idx is None:
            errors.append("[X] Gray callout with 📊 icon not found")
        else:
            checks_passed.append("[C] Gray callout with 📊 icon found")
    
        if heading1_idx is not None and stats_callout_idx <= heading1_idx:
            errors.append("[X] Gray stats callout should appear AFTER heading_1")
        else:
            checks_passed.append("[C] Gray stats callout should appear AFTER heading_1")
    
        # 3. Validate stats callout contains 'Quick Stats' (bold)
        stats_callout = sorted_blocks[stats_callout_idx]
        stats_content = stats_callout.get("content", "")
        stats_props = stats_callout.get("properties", {})
    
        if "quick stats" not in stats_content.lower():
            errors.append("[X] Gray stats callout does not contain 'Quick Stats'")
        else:
            checks_passed.append("[C] Gray stats callout does contains 'Quick Stats'")
    
        # Validate 'Quick Stats' is bold using helper function
        if not _check_text_is_bold(stats_content, stats_props, "Quick Stats"):
            errors.append("[X] Gray stats callout 'Quick Stats' text is not bold (expected **Quick Stats** or bold property)")
        else:
            checks_passed.append("[C] Gray stats callout 'Quick Stats' text is bold (expected **Quick Stats** or bold property)")
    
        # 4. Validate counts in stats callout
        # Look for the count values in the content or in subsequent bullet blocks
        found_total_count = False
        found_yellow_count = False
        found_red_count = False
    
        # Check in callout content itself and following bullets
        check_blocks = [stats_callout]
        for i in range(stats_callout_idx + 1, min(stats_callout_idx + 10, len(sorted_blocks))):
            block = sorted_blocks[i]
            if block.get("type", "").lower() in ["bulletedlist", "bulleted_list"]:
                check_blocks.append(block)
            elif block.get("type", "").lower() in ["heading1", "heading2", "callout"]:
                break
    
        for block in check_blocks:
            content = block.get("content", "").lower()
        
            if "total guidelines" in content:
                if str(total_callouts) in block.get("content", ""):
                    found_total_count = True
        
            if "tips to review" in content:
                if str(yellow_callouts) in block.get("content", ""):
                    found_yellow_count = True
        
            if "critical warnings" in content:
                if str(red_callouts) in block.get("content", ""):
                    found_red_count = True
    
        if not found_total_count:
            errors.append(f"[X] Stats callout missing or incorrect 'Total Guidelines' count. Expected: {total_callouts}")
        else:
            checks_passed.append(f"[C] Stats callout has or incorrect 'Total Guidelines' count. Expected: {total_callouts}")
    
        if not found_yellow_count:
            errors.append(f"[X] Stats callout missing or incorrect 'Tips to Review' count. Expected: {yellow_callouts}")
        else:
            checks_passed.append(f"[C] Stats callout has or incorrect 'Tips to Review' count. Expected: {yellow_callouts}")
    
        if not found_red_count:
            errors.append(f"[X] Stats callout missing or incorrect 'Critical Warnings' count. Expected: {red_callouts}")
        else:
            checks_passed.append(f"[C] Stats callout has or incorrect 'Critical Warnings' count. Expected: {red_callouts}")
    
        # 5. Validate each yellow callout is followed by unchecked todo with correct format
        for yellow_idx in yellow_callout_indices:
            yellow_block = sorted_blocks[yellow_idx]
            yellow_content = yellow_block.get("content", "")
        
            # Expected todo text: first 30 chars + "..."
            first_30_chars = yellow_content[:30]
            expected_todo_prefix = f"📝 Review and apply: {first_30_chars}..."
        
            # Look for todo immediately after this callout
            found_todo = False
            for j in range(yellow_idx + 1, min(yellow_idx + 3, len(sorted_blocks))):
                next_block = sorted_blocks[j]
                next_type = next_block.get("type", "").lower()
                next_content = next_block.get("content", "")
                next_props = next_block.get("properties", {})
            
                if next_type == "todo":
                    is_checked = next_props.get("checked", False)
                    if not is_checked:
                        # Check if content matches expected format
                        if "📝 review and apply:" in next_content.lower():
                            if first_30_chars.lower() in next_content.lower():
                                found_todo = True
                                break
        
            if not found_todo:
                errors.append(f"[X] Missing or incorrect unchecked todo after yellow callout with content starting: '{first_30_chars}...'")
            else:
                checks_passed.append(f"[C] has or incorrect unchecked todo after yellow callout with content starting: '{first_30_chars}...'")
    
        # 6. Validate divider at end of page
        if not sorted_blocks:
            errors.append("[X] No blocks to check for divider")
        else:
            checks_passed.append("[C] blocks to check for divider")
    
        # Check last few blocks for divider
        found_divider = False
        max_order = max(b.get("order", 0) for b in sorted_blocks)
    
        for block in sorted_blocks:
            if block.get("type", "").lower() == "divider":
                block_order = block.get("order", 0)
                # Divider should be near the end
                if block_order >= max_order - 2:
                    found_divider = True
                    break
    
        if not found_divider:
            errors.append("[X] Divider not found at end of page")
        else:
            checks_passed.append("[C] Divider found at end of page")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_agent_add_api_version_tracking(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Task: Navigate to the 'API Documentation' page and implement version tracking. After the main
    heading, insert heading_2 '📚 API Version History'. Add a callout with orange_background and
    ⚡ icon containing bold text 'Current Version: v2.3.1'. Below this, add heading_3
    'v2.3.1 - Latest Release' with a bulleted list: '• Released: January 15, 2024',
    '• Breaking Changes: None', '• New Endpoints: /users/batch, /analytics/custom'. Add heading_3
    'v2.2.0 - Previous Stable' with similar structure. Then analyze the page for any existing
    heading blocks containing 'endpoint' or 'method' (case-insensitive) and create a heading_2
    '🔍 Quick Reference' with a numbered list entry for each found heading: '[X]. [heading text] - [block type]'.
    End with a divider and paragraph with italic text 'Auto-generated index on [today's date]'.
    
    Validates:
    1. 'API Documentation' page exists
    2. heading_2 '📚 API Version History' exists after main heading
    3. Orange callout with ⚡ icon containing 'Current Version: v2.3.1'
    4. heading_3 'v2.3.1 - Latest Release' with bullet points
    5. heading_3 'v2.2.0 - Previous Stable' with bullet structure
    6. heading_2 '🔍 Quick Reference' exists
    7. Numbered list entries for headings containing 'endpoint' or 'method'
    8. Divider before final paragraph
    9. Italic paragraph with current date
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    try:
        from datetime import datetime
    
        # 1. Find API Documentation page using direct query
        api_page = _find_page_by_title_direct(backend, "API Documentation")
        if not api_page:
            errors.append("[X] API Documentation page not found")
        else:
            checks_passed.append("[C] API Documentation page found")
    
        api_page_id = api_page.get("_id")
    
        # Get all blocks for this page using direct query, sorted by order
        page_blocks = _get_blocks_for_page_direct(backend, api_page_id)
        sorted_blocks = sorted(page_blocks, key=lambda x: x.get("order", 0))
    
        if not sorted_blocks:
            errors.append("[X] No blocks found on API Documentation page")
        else:
            checks_passed.append("[C] blocks found on API Documentation page")
    
        # Find key elements
        heading1_idx = None
        version_history_idx = None
        orange_callout_found = False
        latest_release_idx = None
        previous_stable_idx = None
        quick_reference_idx = None
    
        # Also track headings containing 'endpoint' or 'method'
        endpoint_method_headings = []
    
        for i, block in enumerate(sorted_blocks):
            content = block.get("content", "")
            content_lower = content.lower()
            block_type = block.get("type", "").lower()
            props = block.get("properties", {})
        
            if block_type == "heading1":
                heading1_idx = i
        
            if block_type == "heading2":
                if "api version history" in content_lower and "📚" in content:
                    version_history_idx = i
                elif "quick reference" in content_lower and "🔍" in content:
                    quick_reference_idx = i
            
                # Check for endpoint/method headings
                if "endpoint" in content_lower or "method" in content_lower:
                    endpoint_method_headings.append({
                        "text": content,
                        "type": "heading2"
                    })
        
            if block_type == "heading3":
                if "v2.3.1" in content_lower and "latest release" in content_lower:
                    latest_release_idx = i
                elif "v2.2.0" in content_lower and "previous stable" in content_lower:
                    previous_stable_idx = i
            
                # Check for endpoint/method headings
                if "endpoint" in content_lower or "method" in content_lower:
                    endpoint_method_headings.append({
                        "text": content,
                        "type": "heading3"
                    })
        
            if block_type == "callout":
                bg_color = props.get("backgroundColor", "").lower()
                icon = props.get("icon", "")
                if "orange" in bg_color and "⚡" in icon:
                    if "current version" in content_lower and "v2.3.1" in content_lower:
                        # Check for bold formatting using helper (accepts markdown or property)
                        # Still accept without bold for leniency
                        orange_callout_found = True
    
        # 2. Validate heading_2 '📚 API Version History' exists after main heading
        if version_history_idx is None:
            errors.append("[X] heading_2 '📚 API Version History' not found")
        else:
            checks_passed.append("[C] heading_2 '📚 API Version History' found")
    
        if heading1_idx is not None and version_history_idx <= heading1_idx:
            errors.append("[X] heading_2 '📚 API Version History' should appear AFTER main heading")
        else:
            checks_passed.append("[C] heading_2 '📚 API Version History' should appear AFTER main heading")
    
        # 3. Validate orange callout
        if not orange_callout_found:
            errors.append("[X] Orange callout with ⚡ icon containing 'Current Version: v2.3.1' not found")
        else:
            checks_passed.append("[C] Orange callout with ⚡ icon containing 'Current Version: v2.3.1' found")
    
        # 4. Validate v2.3.1 heading and bullet points
        if latest_release_idx is None:
            errors.append("[X] heading_3 'v2.3.1 - Latest Release' not found")
        else:
            checks_passed.append("[C] heading_3 'v2.3.1 - Latest Release' found")
    
        # Check for bullet points after latest release heading
        latest_bullets_found = 0
        for i in range(latest_release_idx + 1, min(latest_release_idx + 6, len(sorted_blocks))):
            block = sorted_blocks[i]
            block_type = block.get("type", "").lower()
            content = block.get("content", "").lower()
        
            if block_type in ["heading2", "heading3"]:
                break
        
            if block_type in ["bulletedlist", "bulleted_list"]:
                if "released" in content or "breaking changes" in content or "new endpoints" in content:
                    latest_bullets_found += 1
    
        if latest_bullets_found < 3:
            errors.append(f"[X] heading_3 'v2.3.1 - Latest Release' missing bullet points. Found {latest_bullets_found}, expected 3")
        else:
            checks_passed.append(f"[C] heading_3 'v2.3.1 - Latest Release' has bullet points. Found {latest_bullets_found}, expected 3")
    
        # 5. Validate v2.2.0 heading
        if previous_stable_idx is None:
            errors.append("[X] heading_3 'v2.2.0 - Previous Stable' not found")
        else:
            checks_passed.append("[C] heading_3 'v2.2.0 - Previous Stable' found")
    
        # 6. Validate Quick Reference heading
        if quick_reference_idx is None:
            errors.append("[X] heading_2 '🔍 Quick Reference' not found")
        else:
            checks_passed.append("[C] heading_2 '🔍 Quick Reference' found")
    
        # 7. Validate numbered list entries for endpoint/method headings
        # The page has heading2 "Endpoints" which contains "endpoint"
        if endpoint_method_headings:
            found_reference_entries = 0
            for i in range(quick_reference_idx + 1, len(sorted_blocks)):
                block = sorted_blocks[i]
                block_type = block.get("type", "").lower()
                content = block.get("content", "").lower()
            
                if block_type in ["heading1", "heading2", "heading3"]:
                    break
            
                if block_type in ["numberedlist", "numbered_list"]:
                    # Check if this references one of the endpoint/method headings
                    for h in endpoint_method_headings:
                        if h["text"].lower() in content:
                            found_reference_entries += 1
        
            if found_reference_entries < len(endpoint_method_headings):
                errors.append(f"[X] Quick Reference missing numbered list entries. Expected {len(endpoint_method_headings)} entries for headings containing 'endpoint' or 'method'")
            else:
                checks_passed.append(f"[C] Quick Reference has numbered list entries. Expected {len(endpoint_method_headings)} entries for headings containing 'endpoint' or 'method'")
    
        # 8 & 9. Validate divider and italic paragraph at end
        found_divider = False
        found_italic_paragraph = False
    
        # Get today's date in common formats
        today = datetime.now()
        date_formats = [
            today.strftime("%B %d, %Y"),  # January 08, 2026
            today.strftime("%Y-%m-%d"),   # 2026-01-08
            today.strftime("%m/%d/%Y"),   # 01/08/2026
            today.strftime("%d/%m/%Y"),   # 08/01/2026
            today.strftime("%B %-d, %Y") if hasattr(today, 'strftime') else "",  # January 8, 2026
        ]
    
        for block in sorted_blocks[-10:]:  # Check last 10 blocks
            block_type = block.get("type", "").lower()
            content = block.get("content", "")
            content_lower = content.lower()
            props = block.get("properties", {})
        
            if block_type == "divider":
                found_divider = True
        
            if block_type == "paragraph":
                if "auto-generated" in content_lower and "index" in content_lower:
                    # Check for italic formatting using helper (accepts markdown or property)
                    # Still accept without italic for leniency
                    # Check for any date format
                    for date_fmt in date_formats:
                        if date_fmt.lower() in content_lower or date_fmt in content:
                            found_italic_paragraph = True
                            break
                    # Also accept if date is present in some form
                    if not found_italic_paragraph:
                        if "2026" in content or "january" in content_lower or "/" in content:
                            found_italic_paragraph = True
    
        if not found_divider:
            errors.append("[X] Divider not found before final paragraph")
        else:
            checks_passed.append("[C] Divider found before final paragraph")
    
        if not found_italic_paragraph:
            errors.append("[X] Italic paragraph with 'Auto-generated index on [today's date]' not found")
        else:
            checks_passed.append("[C] Italic paragraph with 'Auto-generated index on [today's date]' found")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_agent_create_engineering_metrics_report(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Task: Create a new 'Engineering Metrics Report' page as a child of 'Engineering Wiki'.
    Analyze the 'Bug Tracker', 'Feature Requests', and 'Sprint Planning - Jan 15' pages.
    Structure the report: heading_1 '⚙️ Engineering Metrics Report', heading_2 '🐛 Bug Status Overview'
    with a paragraph 'Total bugs tracked: [X]' and 'Resolution rate: [Y]%' where X is total todo
    count in Bug Tracker and Y is percentage of checked todos. Add heading_2 '✨ Feature Pipeline'
    with similar metrics from Feature Requests. Finally, heading_2 '📅 Sprint Health' showing
    'Latest sprint completion: [Z]%' from Sprint Planning page. End with a callout (gray background)
    summarizing: 'Overall engineering health score: [average of all three percentages]%'.
    
    Validates:
    1. 'Engineering Metrics Report' page exists
    2. Page is a child of 'Engineering Wiki' (parentId)
    3. heading_1 '⚙️ Engineering Metrics Report'
    4. heading_2 '🐛 Bug Status Overview' with correct metrics (5 total, 40% resolution)
    5. heading_2 '✨ Feature Pipeline' with correct metrics (3 total, 33% completion)
    6. heading_2 '📅 Sprint Health' with correct metrics (100% completion)
    7. Gray callout with average health score (~58%)
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Find Engineering Metrics Report page using direct query
    try:
        report_page = _find_page_by_title_direct(backend, "Engineering Metrics Report")
        if not report_page:
            errors.append("[X] Engineering Metrics Report page not found")
        else:
            checks_passed.append("[C] Engineering Metrics Report page found")
    
        report_page_id = report_page.get("_id")
    
        # 2. Validate parent is Engineering Wiki using direct query
        wiki_page = _find_page_by_title_direct(backend, "Engineering Wiki")
        if not wiki_page:
            errors.append("[X] Engineering Wiki page not found")
        else:
            checks_passed.append("[C] Engineering Wiki page found")
    
        wiki_id = wiki_page.get("_id")
        if report_page.get("parentId") != wiki_id:
            errors.append(f"[X] Engineering Metrics Report must be a child of Engineering Wiki. Found parentId: {report_page.get('parentId')}, expected: {wiki_id}")
        else:
            checks_passed.append(f"[C] Engineering Metrics Report must be a child of Engineering Wiki. Found parentId: {report_page.get('parentId')}, expected: {wiki_id}")
    
        # Calculate expected metrics from source pages using direct queries
        # Bug Tracker metrics
        bug_page = _find_page_by_title_direct(backend, "Bug Tracker")
        if not bug_page:
            errors.append("[X] Bug Tracker page not found")
        else:
            checks_passed.append("[C] Bug Tracker page found")
    
        bug_blocks = _get_blocks_for_page_direct(backend, bug_page.get("_id"))
        bug_todos = [b for b in bug_blocks if b.get("type") == "todo"]
        bug_total = len(bug_todos)
        bug_checked = sum(1 for t in bug_todos if t.get("properties", {}).get("checked", False))
        bug_percent = int((bug_checked / bug_total * 100)) if bug_total > 0 else 0
    
        # Feature Requests metrics
        feature_page = _find_page_by_title_direct(backend, "Feature Requests")
        if not feature_page:
            errors.append("[X] Feature Requests page not found")
        else:
            checks_passed.append("[C] Feature Requests page found")
    
        feature_blocks = _get_blocks_for_page_direct(backend, feature_page.get("_id"))
        feature_todos = [b for b in feature_blocks if b.get("type") == "todo"]
        feature_total = len(feature_todos)
        feature_checked = sum(1 for t in feature_todos if t.get("properties", {}).get("checked", False))
        feature_percent = int((feature_checked / feature_total * 100)) if feature_total > 0 else 0
    
        # Sprint Planning metrics
        sprint_page = _find_page_by_title_direct(backend, "Sprint Planning - Jan 15")
        if not sprint_page:
            errors.append("[X] Sprint Planning - Jan 15 page not found")
        else:
            checks_passed.append("[C] Sprint Planning - Jan 15 page found")
    
        sprint_blocks = _get_blocks_for_page_direct(backend, sprint_page.get("_id"))
        sprint_todos = [b for b in sprint_blocks if b.get("type") == "todo"]
        sprint_total = len(sprint_todos)
        sprint_checked = sum(1 for t in sprint_todos if t.get("properties", {}).get("checked", False))
        sprint_percent = int((sprint_checked / sprint_total * 100)) if sprint_total > 0 else 0
    
        # Calculate overall average
        overall_percent = int((bug_percent + feature_percent + sprint_percent) / 3)
    
        # Get all blocks for report page using direct query, sorted by order
        page_blocks = _get_blocks_for_page_direct(backend, report_page_id)
        sorted_blocks = sorted(page_blocks, key=lambda x: x.get("order", 0))
    
        if not sorted_blocks:
            errors.append("[X] No blocks found on Engineering Metrics Report page")
        else:
            checks_passed.append("[C] blocks found on Engineering Metrics Report page")
    
        # Validate structure
        found_main_heading = False
        found_bug_section = False
        found_feature_section = False
        found_sprint_section = False
        found_gray_callout = False
    
        bug_metrics_valid = False
        feature_metrics_valid = False
        sprint_metrics_valid = False
    
        current_section = None
    
        for i, block in enumerate(sorted_blocks):
            content = block.get("content", "")
            content_lower = content.lower()
            block_type = block.get("type", "").lower()
            props = block.get("properties", {})
        
            # 3. Check main heading
            if block_type == "heading1" and "engineering metrics report" in content_lower and "⚙️" in content:
                found_main_heading = True
        
            # Check section headings
            if block_type == "heading2":
                if "bug status overview" in content_lower and "🐛" in content:
                    found_bug_section = True
                    current_section = "bug"
                elif "feature pipeline" in content_lower and "✨" in content:
                    found_feature_section = True
                    current_section = "feature"
                elif "sprint health" in content_lower and "📅" in content:
                    found_sprint_section = True
                    current_section = "sprint"
                else:
                    current_section = None
        
            # Check metrics in paragraphs
            if block_type == "paragraph":
                if current_section == "bug":
                    # Check for total and resolution rate
                    if str(bug_total) in content and "total" in content_lower:
                        bug_metrics_valid = True
                    # Allow for slight percentage variation
                    for pct in range(max(0, bug_percent - 5), min(101, bug_percent + 6)):
                        if f"{pct}%" in content or str(pct) in content:
                            if "resolution" in content_lower or "rate" in content_lower:
                                bug_metrics_valid = True
            
                elif current_section == "feature":
                    for pct in range(max(0, feature_percent - 5), min(101, feature_percent + 6)):
                        if f"{pct}%" in content or str(pct) in content:
                            feature_metrics_valid = True
            
                elif current_section == "sprint":
                    for pct in range(max(0, sprint_percent - 5), min(101, sprint_percent + 6)):
                        if f"{pct}%" in content or str(pct) in content:
                            sprint_metrics_valid = True
        
            # 7. Check gray callout with overall health score
            if block_type == "callout":
                bg_color = props.get("backgroundColor", "").lower()
                if "gray" in bg_color:
                    if "overall" in content_lower and "health" in content_lower:
                        # Allow for percentage variation
                        for pct in range(max(0, overall_percent - 10), min(101, overall_percent + 11)):
                            if f"{pct}%" in content or str(pct) in content:
                                found_gray_callout = True
                                break
    
        # Validate all checks
        if not found_main_heading:
            errors.append("[X] heading_1 '⚙️ Engineering Metrics Report' not found")
        else:
            checks_passed.append("[C] heading_1 '⚙️ Engineering Metrics Report' found")
    
        if not found_bug_section:
            errors.append("[X] heading_2 '🐛 Bug Status Overview' not found")
        else:
            checks_passed.append("[C] heading_2 '🐛 Bug Status Overview' found")
    
        if not bug_metrics_valid:
            errors.append(f"[X] Bug Status Overview missing correct metrics. Expected: {bug_total} total, {bug_percent}% resolution rate")
        else:
            checks_passed.append(f"[C] Bug Status Overview has correct metrics. Expected: {bug_total} total, {bug_percent}% resolution rate")
    
        if not found_feature_section:
            errors.append("[X] heading_2 '✨ Feature Pipeline' not found")
        else:
            checks_passed.append("[C] heading_2 '✨ Feature Pipeline' found")
    
        if not feature_metrics_valid:
            errors.append(f"[X] Feature Pipeline missing correct metrics. Expected: ~{feature_percent}% completion")
        else:
            checks_passed.append(f"[C] Feature Pipeline has correct metrics. Expected: ~{feature_percent}% completion")
    
        if not found_sprint_section:
            errors.append("[X] heading_2 '📅 Sprint Health' not found")
        else:
            checks_passed.append("[C] heading_2 '📅 Sprint Health' found")
    
        if not sprint_metrics_valid:
            errors.append(f"[X] Sprint Health missing correct metrics. Expected: {sprint_percent}% completion")
        else:
            checks_passed.append(f"[C] Sprint Health has correct metrics. Expected: {sprint_percent}% completion")
    
        if not found_gray_callout:
            errors.append(f"[X] Gray callout with overall health score not found. Expected: ~{overall_percent}%")
        else:
            checks_passed.append(f"[C] Gray callout with overall health score found. Expected: ~{overall_percent}%")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_agent_insert_risk_assessment_section(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Task: Navigate to 'Comprehensive Product Requirements Document' page and insert a new 'Risk Assessment' subsection.
    
    Prompt: "Navigate to the 'Comprehensive Product Requirements Document' page. Locate the section titled 'Overview - Part 2'. Insert a new 'Risk Assessment' subsection immediately AFTER all the bullet points under 'Overview - Part 2' but BEFORE 'Overview - Part 3'. Add a heading_3 '⚠️ Risk Assessment' with Red color property. Under this, create a two-column layout: Left column titled 'Technical Risks' (bold), right column titled 'Business Risks' (bold). In the Technical Risks column, add a numbered list: '1. Integration complexity with legacy systems', '2. Scalability concerns at 10M+ users', '3. Data migration timeline dependencies'. In the Business Risks column, add a numbered list: '1. Market timing vs competitor launches', '2. Regulatory compliance in EU markets', '3. Resource allocation conflicts'. After the columns, add a callout (Yellow background) with heading 'Mitigation Priority' and text 'Focus on items 1 and 3 in Technical, item 2 in Business for Q1 2024'."
    
    Validates:
    1. Find target page
    2. Locate 'Overview - Part 2' section
    3. Find last bullet point under 'Overview - Part 2'
    4. Locate 'Overview - Part 3' heading
    5. Verify Risk Assessment heading3 exists in correct position with red color
    6. Verify two-column layout exists
    7. Validate left column: 'Technical Risks' with 3 numbered items
    8. Validate right column: 'Business Risks' with 3 numbered items
    9. Validate yellow callout after columns
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Find target page
    try:
        prd_page = _find_page_by_title(final_state_backend, "Comprehensive Product Requirements Document")
        if not prd_page:
            errors.append("[X] Page 'Comprehensive Product Requirements Document' not found")
        else:
            checks_passed.append("[C] Page 'Comprehensive Product Requirements Document' found")
    
        page_id = prd_page.get("_id")
        if not page_id:
            errors.append("[X] Comprehensive Product Requirements Document page has no _id")
        else:
            checks_passed.append("[C] Comprehensive Product Requirements Document page has _id")
    
        # Get all blocks for the page
        blocks = _get_blocks_for_page(final_state_backend, page_id)
        if not blocks:
            errors.append("[X] Page has no content blocks")
        else:
            checks_passed.append("[C] Page has content blocks")
    
        blocks.sort(key=lambda b: b.get("order", 0))
    
        # 2. Locate 'Overview - Part 2' section
        overview_part2_order = None
        for block in blocks:
            if block.get("type") == "heading3":
                content_lower = block.get("content", "").lower()
                if "overview - part 2" in content_lower or "overview part 2" in content_lower:
                    overview_part2_order = block.get("order", 0)
                    break
    
        if overview_part2_order is None:
            errors.append("[X] Heading 'Overview - Part 2' not found")
        else:
            checks_passed.append("[C] Heading 'Overview - Part 2' found")
    
        # 3. Find last bullet point under 'Overview - Part 2'
        last_bullet_order = None
        for block in blocks:
            order = block.get("order", 0)
            if order > overview_part2_order:
                # Check if we've hit Overview - Part 3
                if block.get("type") == "heading3":
                    content_lower = block.get("content", "").lower()
                    if "overview - part 3" in content_lower or "overview part 3" in content_lower:
                        break
                # Track bulletedList blocks
                if block.get("type") == "bulletedList":
                    last_bullet_order = order
    
        if last_bullet_order is None:
            errors.append("[X] No bullet points found under 'Overview - Part 2'")
        else:
            checks_passed.append("[C] bullet points found under 'Overview - Part 2'")
    
        # 4. Locate 'Overview - Part 3' heading
        overview_part3_order = None
        for block in blocks:
            if block.get("type") == "heading3":
                content_lower = block.get("content", "").lower()
                if "overview - part 3" in content_lower or "overview part 3" in content_lower:
                    overview_part3_order = block.get("order", 0)
                    break
    
        if overview_part3_order is None:
            errors.append("[X] Heading 'Overview - Part 3' not found")
        else:
            checks_passed.append("[C] Heading 'Overview - Part 3' found")
    
        # 5. Verify Risk Assessment heading3 exists in correct position with red color
        risk_assessment_heading = None
        risk_assessment_order = None
        for block in blocks:
            order = block.get("order", 0)
            if block.get("type") == "heading3":
                content_lower = block.get("content", "").lower()
                if "risk assessment" in content_lower:
                    if last_bullet_order < order < overview_part3_order:
                        risk_assessment_heading = block
                        risk_assessment_order = order
                        break
    
        if risk_assessment_heading is None:
            errors.append("[X] Risk Assessment heading3 not found in correct position (after last bullet, before Overview - Part 3)")
        else:
            checks_passed.append("[C] Risk Assessment heading3 found in correct position (after last bullet, before Overview - Part 3)")
    
        # Check red color property
        props = risk_assessment_heading.get("properties", {})
        color = props.get("color", "").lower()
        if "red" not in color:
            errors.append(f"[X] Risk Assessment heading3 must have Red color property. Found: '{color}'")
        else:
            checks_passed.append(f"[C] Risk Assessment heading3 must have Red color property. Found: '{color}'")
    
        # 6. Verify two-column layout exists
        columns_block = None
        for block in blocks:
            order = block.get("order", 0)
            if order > risk_assessment_order and order < overview_part3_order:
                if block.get("type") == "columns":
                    columns_block = block
                    break
    
        if columns_block is None:
            errors.append("[X] Two-column layout not found after Risk Assessment heading")
        else:
            checks_passed.append("[C] Two-column layout found after Risk Assessment heading")
    
        # Get column children (blocks with parentId matching columns block)
        columns_id = columns_block.get("_id")
        column_blocks = [b for b in blocks if b.get("parentId") == columns_id]
    
        if len(column_blocks) < 2:
            errors.append(f"[X] Columns block should have 2 column children. Found: {len(column_blocks)}")
        else:
            checks_passed.append(f"[C] Columns block should have 2 column children. Found: {len(column_blocks)}")
    
        # Sort columns by order
        column_blocks.sort(key=lambda b: b.get("order", 0))
        left_column = column_blocks[0]
        right_column = column_blocks[1]
    
        # Get blocks within each column
        left_column_blocks = [b for b in blocks if b.get("parentId") == left_column.get("_id")]
        right_column_blocks = [b for b in blocks if b.get("parentId") == right_column.get("_id")]
    
        # 7. Validate left column: 'Technical Risks'
        has_technical_risks_title = False
        technical_risks_items = []
    
        for block in left_column_blocks:
            content = block.get("content", "")
            content_lower = content.lower()
            props = block.get("properties", {})
        
            # Check for bold "Technical Risks" title
            if "technical risks" in content_lower:
                if _check_text_is_bold(content, props, "Technical Risks"):
                    has_technical_risks_title = True
        
            # Collect numbered list items
            if block.get("type") == "numberedList":
                technical_risks_items.append(content_lower)
    
        if not has_technical_risks_title:
            errors.append("[X] Left column missing bold 'Technical Risks' title")
        else:
            checks_passed.append("[C] Left column has bold 'Technical Risks' title")
    
        # Check for exact 3 numbered items
        required_technical = [
            "integration complexity with legacy systems",
            "scalability concerns at 10m+ users",
            "data migration timeline dependencies"
        ]
    
        found_technical = 0
        for req in required_technical:
            for item in technical_risks_items:
                if req in item:
                    found_technical += 1
                    break
    
        if found_technical < 3:
            errors.append(f"[X] Technical Risks column missing required numbered items. Found {found_technical}/3")
        else:
            checks_passed.append(f"[C] Technical Risks column has required numbered items. Found {found_technical}/3")
    
        # 8. Validate right column: 'Business Risks'
        has_business_risks_title = False
        business_risks_items = []
    
        for block in right_column_blocks:
            content = block.get("content", "")
            content_lower = content.lower()
            props = block.get("properties", {})
        
            # Check for bold "Business Risks" title
            if "business risks" in content_lower:
                if _check_text_is_bold(content, props, "Business Risks"):
                    has_business_risks_title = True
        
            # Collect numbered list items
            if block.get("type") == "numberedList":
                business_risks_items.append(content_lower)
    
        if not has_business_risks_title:
            errors.append("[X] Right column missing bold 'Business Risks' title")
        else:
            checks_passed.append("[C] Right column has bold 'Business Risks' title")
    
        # Check for exact 3 numbered items
        required_business = [
            "market timing vs competitor launches",
            "regulatory compliance in eu markets",
            "resource allocation conflicts"
        ]
    
        found_business = 0
        for req in required_business:
            for item in business_risks_items:
                if req in item:
                    found_business += 1
                    break
    
        if found_business < 3:
            errors.append(f"[X] Business Risks column missing required numbered items. Found {found_business}/3")
        else:
            checks_passed.append(f"[C] Business Risks column has required numbered items. Found {found_business}/3")
    
        # 9. Validate yellow callout after columns
        columns_order = columns_block.get("order", 0)
        yellow_callout = None
    
        for block in blocks:
            order = block.get("order", 0)
            if order > columns_order and order < overview_part3_order:
                if block.get("type") == "callout":
                    props = block.get("properties", {})
                    bg_color = props.get("backgroundColor", "").lower()
                    if "yellow" in bg_color:
                        yellow_callout = block
                        break
    
        if yellow_callout is None:
            errors.append("[X] Yellow callout not found after columns")
        else:
            checks_passed.append("[C] Yellow callout found after columns")
    
        callout_content = yellow_callout.get("content", "").lower()
        if "mitigation priority" not in callout_content:
            errors.append("[X] Yellow callout missing 'Mitigation Priority' heading")
        else:
            checks_passed.append("[C] Yellow callout has 'Mitigation Priority' heading")
    
        if "focus on items 1 and 3 in technical" not in callout_content:
            errors.append("[X] Yellow callout missing required mitigation priority text")
        else:
            checks_passed.append("[C] Yellow callout has required mitigation priority text")
    
        if "item 2 in business for q1 2024" not in callout_content:
            errors.append("[X] Yellow callout missing Q1 2024 reference")
        else:
            checks_passed.append("[C] Yellow callout has Q1 2024 reference")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_agent_create_documentation_hierarchy_report(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Task: Create a new 'Documentation Hierarchy Report' page as a child of 'Project Documentation'.
    
    Prompt: "Create a new 'Documentation Hierarchy Report' page as a child of 'Project Documentation'. Fetch the Project Documentation page and all its descendants (Architecture and sub-pages). Build a comprehensive report with: heading_1 '📚 Documentation Structure Analysis', then a code block of type 'text' showing the hierarchy tree using exact format: 'Project Documentation └─ Architecture ├─ Frontend Architecture │ ├─ Component Library │ └─ State Management └─ Backend Architecture └─ API Design Patterns'. Below add heading_2 '📊 Page Metrics' with a table-like structure using paragraphs: 'Total pages in hierarchy: [COUNT]', 'Deepest nesting level: 3', 'Pages marked as favorite: [list page titles]'."
    
    Validates:
    1. Find 'Project Documentation' page
    2. Verify 'Documentation Hierarchy Report' page exists
    3. Verify parent-child relationship
    4. Verify heading1 '📚 Documentation Structure Analysis'
    5. Verify code block with exact hierarchy tree
    6. Verify heading2 '📊 Page Metrics'
    7. Validate metrics content
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Find 'Project Documentation' page
    try:
        project_doc_page = _find_page_by_title(final_state_backend, "Project Documentation")
        if not project_doc_page:
            errors.append("[X] Page 'Project Documentation' not found")
        else:
            checks_passed.append("[C] Page 'Project Documentation' found")
    
        project_doc_id = project_doc_page.get("_id")
    
        # 2. Verify 'Documentation Hierarchy Report' page exists
        report_page = _find_page_by_title(final_state_backend, "Documentation Hierarchy Report")
        if not report_page:
            errors.append("[X] Page 'Documentation Hierarchy Report' not found")
        else:
            checks_passed.append("[C] Page 'Documentation Hierarchy Report' found")
    
        report_page_id = report_page.get("_id")
    
        # 3. Verify parent-child relationship
        if report_page.get("parentId") != project_doc_id:
            errors.append(f"[X] Documentation Hierarchy Report must be a child of Project Documentation. Found parentId: {report_page.get('parentId')}, expected: {project_doc_id}")
        else:
            checks_passed.append(f"[C] Documentation Hierarchy Report must be a child of Project Documentation. Found parentId: {report_page.get('parentId')}, expected: {project_doc_id}")
    
        # Get all blocks for report page
        blocks = _get_blocks_for_page(final_state_backend, report_page_id)
        if not blocks:
            errors.append("[X] Documentation Hierarchy Report page has no content blocks")
        else:
            checks_passed.append("[C] Documentation Hierarchy Report page has content blocks")
    
        blocks.sort(key=lambda b: b.get("order", 0))
    
        # 4. Verify heading1 '📚 Documentation Structure Analysis'
        has_analysis_heading = False
        for block in blocks:
            if block.get("type") == "heading1":
                content_lower = block.get("content", "").lower()
                if "documentation structure analysis" in content_lower:
                    has_analysis_heading = True
                    break
    
        if not has_analysis_heading:
            errors.append("[X] Missing heading1 '📚 Documentation Structure Analysis'")
        else:
            checks_passed.append("[C] has heading1 '📚 Documentation Structure Analysis'")
    
        # 5. Verify code block with exact hierarchy tree
        code_block_found = False
        expected_tree_parts = [
            "project documentation",
            "└─ architecture",
            "├─ frontend architecture",
            "│ ├─ component library",
            "│ └─ state management",
            "└─ backend architecture",
            "└─ api design patterns"
        ]
    
        for block in blocks:
            if block.get("type") == "code":
                props = block.get("properties", {})
                language = props.get("language", "").lower()
                content = block.get("content", "").lower()
            
                # Check if it's text type or language is text
                if language == "text" or language == "":
                    # Check for all expected tree parts
                    all_parts_found = all(part in content for part in expected_tree_parts)
                    if all_parts_found:
                        code_block_found = True
                        break
    
        if not code_block_found:
            errors.append("[X] Code block with exact hierarchy tree structure not found")
        else:
            checks_passed.append("[C] Code block with exact hierarchy tree structure found")
    
        # 6. Verify heading2 '📊 Page Metrics'
        has_metrics_heading = False
        for block in blocks:
            if block.get("type") == "heading2":
                content_lower = block.get("content", "").lower()
                if "page metrics" in content_lower:
                    has_metrics_heading = True
                    break
    
        if not has_metrics_heading:
            errors.append("[X] Missing heading2 '📊 Page Metrics'")
        else:
            checks_passed.append("[C] has heading2 '📊 Page Metrics'")
    
        # 7. Validate metrics content
        # Recursively get all pages under Project Documentation
        def get_all_descendants(parent_id: str) -> List[Dict[str, Any]]:
            descendants = []
            children = _get_child_pages(final_state_backend, parent_id)
            for page in children:
                descendants.append(page)
                descendants.extend(get_all_descendants(page.get("_id")))
            return descendants
    
        all_descendants = get_all_descendants(project_doc_id)
        total_pages = len(all_descendants) + 1  # +1 for Project Documentation itself
    
        # Calculate deepest nesting level
        def get_max_depth(page_id: str, current_depth: int = 0) -> int:
            max_depth = current_depth
            children = _get_child_pages(final_state_backend, page_id)
            for page in children:
                depth = get_max_depth(page.get("_id"), current_depth + 1)
                max_depth = max(max_depth, depth)
            return max_depth
    
        max_depth = get_max_depth(project_doc_id)
    
        # Find favorite pages
        favorite_pages = [p for p in all_descendants if p.get("isFavorite", False)]
        favorite_titles = [p.get("title", "") for p in favorite_pages]
    
        # Check for metrics in paragraph blocks
        has_total_count = False
        has_depth_3 = False
        has_favorites_list = False
    
        for block in blocks:
            if block.get("type") == "paragraph":
                content = block.get("content", "")
                content_lower = content.lower()
            
                if "total pages in hierarchy" in content_lower:
                    if str(total_pages) in content:
                        has_total_count = True
            
                if "deepest nesting level: 3" in content_lower:
                    has_depth_3 = True
            
                if "pages marked as favorite" in content_lower:
                    # Check if favorite titles are listed
                    if favorite_titles:
                        for title in favorite_titles:
                            if title.lower() in content_lower:
                                has_favorites_list = True
                                break
                    else:
                        # No favorites, but the text should still be present
                        has_favorites_list = True
    
        if not has_total_count:
            errors.append(f"[X] Missing or incorrect 'Total pages in hierarchy' count. Expected: {total_pages}")
        else:
            checks_passed.append(f"[C] has or incorrect 'Total pages in hierarchy' count. Expected: {total_pages}")
    
        if not has_depth_3:
            errors.append("[X] Missing 'Deepest nesting level: 3' in metrics")
        else:
            checks_passed.append("[C] has 'Deepest nesting level: 3' in metrics")
    
        if not has_favorites_list:
            errors.append("[X] Missing or incorrect 'Pages marked as favorite' list")
        else:
            checks_passed.append("[C] has or incorrect 'Pages marked as favorite' list")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_agent_insert_content_in_onboarding_guide(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Task: On the 'Onboarding Guide' page, insert new content between the 'First Day Tasks' section and the numbered list.
    
    Prompt: "On the 'Onboarding Guide' page, insert new content between the 'First Day Tasks' section and the numbered list that follows it. Add a callout block with green_background and '🎉' icon containing text 'Welcome aboard! Your first day is crucial for setting the right foundation.' Then add a paragraph with text 'Before diving into tasks, ensure you have:' followed by a bulletedList with exactly these items: '• Access to all necessary systems', '• Your workspace properly configured', '• Emergency contact information saved'. The formatting must match the existing numbered list style but use bullets instead."
    
    Validates:
    1. Find 'Onboarding Guide' page
    2. Locate 'First Day Tasks' heading
    3. Find numbered list after 'First Day Tasks'
    4. Verify green callout exists between heading and numbered list
    5. Verify paragraph before bulleted list
    6. Verify bulleted list with exact items
    7. Verify positioning relative to numbered list
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Find 'Onboarding Guide' page using direct query
    try:
        onboarding_page = _find_page_by_title_direct(backend, "Onboarding Guide")
        if not onboarding_page:
            errors.append("[X] Page 'Onboarding Guide' not found")
        else:
            checks_passed.append("[C] Page 'Onboarding Guide' found")
    
        page_id = onboarding_page.get("_id")
        if not page_id:
            errors.append("[X] Onboarding Guide page has no _id")
        else:
            checks_passed.append("[C] Onboarding Guide page has _id")
    
        # Get all blocks for the page using direct query
        blocks = _get_blocks_for_page_direct(backend, page_id)
        if not blocks:
            errors.append("[X] Page 'Onboarding Guide' has no content blocks")
        else:
            checks_passed.append("[C] Page 'Onboarding Guide' has content blocks")
    
        blocks.sort(key=lambda b: b.get("order", 0))
    
        # 2. Locate 'First Day Tasks' heading
        first_day_tasks_order = None
        for block in blocks:
            if block.get("type") in ["heading2", "heading3"]:
                content_lower = block.get("content", "").lower()
                if "first day tasks" in content_lower:
                    first_day_tasks_order = block.get("order", 0)
                    break
    
        if first_day_tasks_order is None:
            errors.append("[X] Heading 'First Day Tasks' not found")
        else:
            checks_passed.append("[C] Heading 'First Day Tasks' found")
    
        # 3. Find numbered list after 'First Day Tasks'
        numbered_list_order = None
        for block in blocks:
            order = block.get("order", 0)
            if order > first_day_tasks_order:
                if block.get("type") == "numberedList":
                    numbered_list_order = order
                    break
    
        if numbered_list_order is None:
            errors.append("[X] Numbered list not found after 'First Day Tasks' heading")
        else:
            checks_passed.append("[C] Numbered list found after 'First Day Tasks' heading")
    
        # 4. Verify green callout exists between heading and numbered list
        green_callout = None
        for block in blocks:
            order = block.get("order", 0)
            if first_day_tasks_order < order < numbered_list_order:
                if block.get("type") == "callout":
                    props = block.get("properties", {})
                    bg_color = props.get("backgroundColor", "").lower()
                    icon = props.get("icon", "")
                    if "green" in bg_color and "🎉" in icon:
                        content = block.get("content", "")
                        if "welcome aboard" in content.lower() and "first day is crucial" in content.lower():
                            green_callout = block
                            break
    
        if green_callout is None:
            errors.append("[X] Green callout with 🎉 icon not found between 'First Day Tasks' and numbered list")
        else:
            checks_passed.append("[C] Green callout with 🎉 icon found between 'First Day Tasks' and numbered list")
    
        # 5. Verify paragraph before bulleted list
        callout_order = green_callout.get("order", 0)
        has_intro_paragraph = False
        for block in blocks:
            order = block.get("order", 0)
            if callout_order < order < numbered_list_order:
                if block.get("type") == "paragraph":
                    content_lower = block.get("content", "").lower()
                    if "before diving into tasks, ensure you have" in content_lower:
                        has_intro_paragraph = True
                        break
    
        if not has_intro_paragraph:
            errors.append("[X] Missing paragraph with 'Before diving into tasks, ensure you have:'")
        else:
            checks_passed.append("[C] has paragraph with 'Before diving into tasks, ensure you have:'")
    
        # 6. Verify bulleted list with exact items
        required_items = [
            "access to all necessary systems",
            "your workspace properly configured",
            "emergency contact information saved"
        ]
    
        bulleted_list_found = False
        found_items = []
    
        for block in blocks:
            order = block.get("order", 0)
            if callout_order < order < numbered_list_order:
                if block.get("type") == "bulletedList":
                    bulleted_list_found = True
                    content_lower = block.get("content", "").lower()
                    for req in required_items:
                        if req in content_lower:
                            found_items.append(req)
    
        if not bulleted_list_found:
            errors.append("[X] Bulleted list not found after paragraph")
        else:
            checks_passed.append("[C] Bulleted list found after paragraph")
    
        if len(found_items) < 3:
            missing = [item for item in required_items if item not in found_items]
            errors.append(f"[X] Bulleted list missing required items: {missing}")
        else:
            checks_passed.append(f"[C] Bulleted list has required items: {has}")
    
        # 7. Verify positioning - all new content is between heading and numbered list
        # Already verified above
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_agent_insert_infrastructure_section(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Task: Navigate to 'Engineering Wiki' page and insert a new 'Infrastructure' heading3.
    
    Prompt: "Navigate to the 'Engineering Wiki' page and locate the 'Tech Stack' section. Insert a new heading3 block with text 'Infrastructure' immediately AFTER the last bulletedList block under 'Tech Stack' (after 'Database: MongoDB') but BEFORE the 'Development Setup' heading2. Under this new 'Infrastructure' heading, add exactly three bulletedList blocks with the following texts in order: 'Cloud Provider: AWS', 'Container Orchestration: Kubernetes', and 'CI/CD: GitHub Actions'. Then, at the very end of the page (after the last paragraph about .env values), add a divider block followed by a callout block with green_background, icon '✅', and content 'Remember: All infrastructure changes must be reviewed by the DevOps team before deployment.'"
    
    Validates:
    1. Find 'Engineering Wiki' page
    2. Locate 'Tech Stack' section
    3. Find last bulletedList under 'Tech Stack'
    4. Locate 'Development Setup' heading
    5. Verify 'Infrastructure' heading3 exists in correct position
    6. Verify three bulletedList blocks under Infrastructure
    7. Find last paragraph about .env values
    8. Verify divider after .env paragraph
    9. Verify green callout after divider
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Find 'Engineering Wiki' page using direct query
    try:
        wiki_page = _find_page_by_title_direct(backend, "Engineering Wiki")
        if not wiki_page:
            errors.append("[X] Page 'Engineering Wiki' not found")
        else:
            checks_passed.append("[C] Page 'Engineering Wiki' found")
    
        page_id = wiki_page.get("_id")
        if not page_id:
            errors.append("[X] Engineering Wiki page has no _id")
        else:
            checks_passed.append("[C] Engineering Wiki page has _id")
    
        # Get all blocks for the page using direct query
        blocks = _get_blocks_for_page_direct(backend, page_id)
        if not blocks:
            errors.append("[X] Page 'Engineering Wiki' has no content blocks")
        else:
            checks_passed.append("[C] Page 'Engineering Wiki' has content blocks")
    
        blocks.sort(key=lambda b: b.get("order", 0))
    
        # 2. Locate 'Tech Stack' section
        tech_stack_order = None
        for block in blocks:
            if block.get("type") == "heading2":
                content_lower = block.get("content", "").lower()
                if "tech stack" in content_lower:
                    tech_stack_order = block.get("order", 0)
                    break
    
        if tech_stack_order is None:
            errors.append("[X] Heading 'Tech Stack' not found")
        else:
            checks_passed.append("[C] Heading 'Tech Stack' found")
    
        # 3. Find last bulletedList under 'Tech Stack' (containing Database: MongoDB)
        last_bullet_order = None
        for block in blocks:
            order = block.get("order", 0)
            if order > tech_stack_order:
                # Check if we've hit Development Setup
                if block.get("type") == "heading2":
                    content_lower = block.get("content", "").lower()
                    if "development setup" in content_lower:
                        break
                # Track bulletedList with Database: MongoDB
                if block.get("type") == "bulletedList":
                    content_lower = block.get("content", "").lower()
                    if "database" in content_lower and "mongodb" in content_lower:
                        last_bullet_order = order
    
        if last_bullet_order is None:
            errors.append("[X] Last bulletedList with 'Database: MongoDB' not found under 'Tech Stack'")
        else:
            checks_passed.append("[C] Last bulletedList with 'Database: MongoDB' found under 'Tech Stack'")
    
        # 4. Locate 'Development Setup' heading
        dev_setup_order = None
        for block in blocks:
            if block.get("type") == "heading2":
                content_lower = block.get("content", "").lower()
                if "development setup" in content_lower:
                    dev_setup_order = block.get("order", 0)
                    break
    
        if dev_setup_order is None:
            errors.append("[X] Heading 'Development Setup' not found")
        else:
            checks_passed.append("[C] Heading 'Development Setup' found")
    
        # 5. Verify 'Infrastructure' heading3 exists in correct position
        infrastructure_heading = None
        infrastructure_order = None
        for block in blocks:
            order = block.get("order", 0)
            if block.get("type") == "heading3":
                content_lower = block.get("content", "").lower()
                if content_lower == "infrastructure" or content_lower.strip() == "infrastructure":
                    if last_bullet_order < order < dev_setup_order:
                        infrastructure_heading = block
                        infrastructure_order = order
                        break
    
        if infrastructure_heading is None:
            errors.append("[X] Infrastructure heading3 not found in correct position (after Database: MongoDB bullet, before Development Setup)")
        else:
            checks_passed.append("[C] Infrastructure heading3 found in correct position (after Database: MongoDB bullet, before Development Setup)")
    
        # 6. Verify three bulletedList blocks under Infrastructure
        required_bullets = [
            "cloud provider: aws",
            "container orchestration: kubernetes",
            "ci/cd: github actions"
        ]
    
        infrastructure_bullets = []
        for block in blocks:
            order = block.get("order", 0)
            if infrastructure_order < order < dev_setup_order:
                if block.get("type") == "bulletedList":
                    content_lower = block.get("content", "").lower()
                    infrastructure_bullets.append(content_lower)
    
        if len(infrastructure_bullets) < 3:
            errors.append(f"[X] Infrastructure section should have 3 bulletedList blocks. Found: {len(infrastructure_bullets)}")
        else:
            checks_passed.append(f"[C] Infrastructure section should have 3 bulletedList blocks. Found: {len(infrastructure_bullets)}")
    
        found_bullets = 0
        for req in required_bullets:
            for bullet in infrastructure_bullets:
                if req in bullet:
                    found_bullets += 1
                    break
    
        if found_bullets < 3:
            errors.append(f"[X] Infrastructure section missing required bullet items. Found {found_bullets}/3")
        else:
            checks_passed.append(f"[C] Infrastructure section has required bullet items. Found {found_bullets}/3")
    
        # 7. Find last paragraph about .env values
        env_paragraph_order = None
        for block in blocks:
            if block.get("type") == "paragraph":
                content_lower = block.get("content", "").lower()
                if ".env" in content_lower or "copy .env.example" in content_lower:
                    env_paragraph_order = block.get("order", 0)
    
        if env_paragraph_order is None:
            errors.append("[X] Paragraph about .env values not found")
        else:
            checks_passed.append("[C] Paragraph about .env values found")
    
        # 8. Verify divider after .env paragraph
        divider_found = False
        for block in blocks:
            order = block.get("order", 0)
            if order > env_paragraph_order:
                if block.get("type") == "divider":
                    divider_found = True
                    divider_order = order
                    break
    
        if not divider_found:
            errors.append("[X] Divider not found after .env paragraph")
        else:
            checks_passed.append("[C] Divider found after .env paragraph")
    
        # 9. Verify green callout after divider
        green_callout_found = False
        for block in blocks:
            order = block.get("order", 0)
            if order > divider_order:
                if block.get("type") == "callout":
                    props = block.get("properties", {})
                    bg_color = props.get("backgroundColor", "").lower()
                    icon = props.get("icon", "")
                    content = block.get("content", "")
                
                    if "green" in bg_color and ("✅" in icon or "check" in icon.lower()):
                        if "infrastructure changes must be reviewed" in content.lower() and "devops team" in content.lower():
                            green_callout_found = True
                            break
    
        if not green_callout_found:
            errors.append("[X] Green callout with ✅ icon and DevOps review text not found after divider")
        else:
            checks_passed.append("[C] Green callout with ✅ icon and DevOps review text found after divider")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_agent_reorganize_product_specs_page(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Task: Perform a comprehensive reorganization of the 'Product Specs' page.
    
    Prompt: "Perform a comprehensive reorganization of the 'Product Specs' page. Start by adding heading1 '📐 Product Specification Document v2.0'. Add heading2 '⚠️ Specification Status' with a callout using red_background, icon '🔴', containing 'DRAFT - Pending review by Product Council'. Create heading2 '🎯 Core Features' with subheadings using heading3: '🔐 Authentication & Security', '📊 Analytics Dashboard', and '🔗 Integration APIs'. Under Authentication, add a code block with 'interface AuthConfig { provider: OAuth2 | SAML | LDAP; mfa: boolean; sessionTimeout: number; }' with language 'typescript'. Under Analytics, add a bulletedList: 'Real-time data visualization', 'Custom report builder', 'Automated insights with ML'. Under Integration, add a numberedList: '1. REST API v2', '2. GraphQL endpoint', '3. Webhook subscriptions'. Finally, add the Team Directory's team photo image at the bottom with caption 'Product team collaborative session - January 2024'."
    
    Validates:
    1. Find 'Product Specs' page
    2. Verify heading1 '📐 Product Specification Document v2.0'
    3. Verify heading2 '⚠️ Specification Status'
    4. Verify red callout under status
    5. Verify heading2 '🎯 Core Features'
    6. Verify heading3 '🔐 Authentication & Security'
    7. Verify TypeScript code block under Authentication
    8. Verify heading3 '📊 Analytics Dashboard'
    9. Verify bulletedList under Analytics
    10. Verify heading3 '🔗 Integration APIs'
    11. Verify numberedList under Integration
    12. Verify team photo image at bottom
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Find 'Product Specs' page using direct query
    try:
        product_specs_page = _find_page_by_title_direct(backend, "Product Specs")
        if not product_specs_page:
            errors.append("[X] Page 'Product Specs' not found")
        else:
            checks_passed.append("[C] Page 'Product Specs' found")
    
        page_id = product_specs_page.get("_id")
        if not page_id:
            errors.append("[X] Product Specs page has no _id")
        else:
            checks_passed.append("[C] Product Specs page has _id")
    
        # Get all blocks for the page using direct query
        blocks = _get_blocks_for_page_direct(backend, page_id)
        if not blocks:
            errors.append("[X] Page 'Product Specs' has no content blocks")
        else:
            checks_passed.append("[C] Page 'Product Specs' has content blocks")
    
        blocks.sort(key=lambda b: b.get("order", 0))
    
        # 2. Verify heading1 '📐 Product Specification Document v2.0'
        has_v2_heading = False
        for block in blocks:
            if block.get("type") == "heading1":
                content_lower = block.get("content", "").lower()
                if "product specification document v2.0" in content_lower:
                    has_v2_heading = True
                    break
    
        if not has_v2_heading:
            errors.append("[X] Missing heading1 '📐 Product Specification Document v2.0'")
        else:
            checks_passed.append("[C] has heading1 '📐 Product Specification Document v2.0'")
    
        # 3. Verify heading2 '⚠️ Specification Status'
        has_status_heading = False
        status_heading_order = None
        for block in blocks:
            if block.get("type") == "heading2":
                content_lower = block.get("content", "").lower()
                if "specification status" in content_lower:
                    has_status_heading = True
                    status_heading_order = block.get("order", 0)
                    break
    
        if not has_status_heading:
            errors.append("[X] Missing heading2 '⚠️ Specification Status'")
        else:
            checks_passed.append("[C] has heading2 '⚠️ Specification Status'")
    
        # 4. Verify red callout under status
        has_red_callout = False
        for block in blocks:
            order = block.get("order", 0)
            if order > status_heading_order:
                if block.get("type") == "callout":
                    props = block.get("properties", {})
                    bg_color = props.get("backgroundColor", "").lower()
                    icon = props.get("icon", "")
                    content = block.get("content", "")
                
                    if "red" in bg_color and "🔴" in icon:
                        if "draft" in content.lower() and "pending review by product council" in content.lower():
                            has_red_callout = True
                            break
    
        if not has_red_callout:
            errors.append("[X] Missing red callout with 🔴 icon containing 'DRAFT - Pending review by Product Council'")
        else:
            checks_passed.append("[C] has red callout with 🔴 icon containing 'DRAFT - Pending review by Product Council'")
    
        # 5. Verify heading2 '🎯 Core Features'
        has_core_features = False
        core_features_order = None
        for block in blocks:
            if block.get("type") == "heading2":
                content_lower = block.get("content", "").lower()
                if "core features" in content_lower:
                    has_core_features = True
                    core_features_order = block.get("order", 0)
                    break
    
        if not has_core_features:
            errors.append("[X] Missing heading2 '🎯 Core Features'")
        else:
            checks_passed.append("[C] has heading2 '🎯 Core Features'")
    
        # 6. Verify heading3 '🔐 Authentication & Security'
        has_auth_heading = False
        auth_heading_order = None
        for block in blocks:
            if block.get("type") == "heading3":
                content_lower = block.get("content", "").lower()
                if "authentication" in content_lower and "security" in content_lower:
                    has_auth_heading = True
                    auth_heading_order = block.get("order", 0)
                    break
    
        if not has_auth_heading:
            errors.append("[X] Missing heading3 '🔐 Authentication & Security'")
        else:
            checks_passed.append("[C] has heading3 '🔐 Authentication & Security'")
    
        # 7. Verify TypeScript code block under Authentication
        has_typescript_code = False
        for block in blocks:
            order = block.get("order", 0)
            if order > auth_heading_order:
                if block.get("type") == "code":
                    props = block.get("properties", {})
                    language = props.get("language", "").lower()
                    content = block.get("content", "")
                
                    if language == "typescript":
                        if "interface authconfig" in content.lower():
                            if "provider: oauth2 | saml | ldap" in content.lower():
                                if "mfa: boolean" in content.lower() and "sessiontimeout: number" in content.lower():
                                    has_typescript_code = True
                                    break
    
        if not has_typescript_code:
            errors.append("[X] Missing TypeScript code block with AuthConfig interface under Authentication")
        else:
            checks_passed.append("[C] has TypeScript code block with AuthConfig interface under Authentication")
    
        # 8. Verify heading3 '📊 Analytics Dashboard'
        has_analytics_heading = False
        analytics_heading_order = None
        for block in blocks:
            if block.get("type") == "heading3":
                content_lower = block.get("content", "").lower()
                if "analytics dashboard" in content_lower:
                    has_analytics_heading = True
                    analytics_heading_order = block.get("order", 0)
                    break
    
        if not has_analytics_heading:
            errors.append("[X] Missing heading3 '📊 Analytics Dashboard'")
        else:
            checks_passed.append("[C] has heading3 '📊 Analytics Dashboard'")
    
        # 9. Verify bulletedList under Analytics
        required_analytics = [
            "real-time data visualization",
            "custom report builder",
            "automated insights with ml"
        ]
    
        analytics_items_found = 0
        for block in blocks:
            order = block.get("order", 0)
            if order > analytics_heading_order:
                if block.get("type") == "bulletedList":
                    content_lower = block.get("content", "").lower()
                    for req in required_analytics:
                        if req in content_lower:
                            analytics_items_found += 1
                            break
    
        if analytics_items_found < 3:
            errors.append(f"[X] Analytics section missing required bullet items. Found {analytics_items_found}/3")
        else:
            checks_passed.append(f"[C] Analytics section has required bullet items. Found {analytics_items_found}/3")
    
        # 10. Verify heading3 '🔗 Integration APIs'
        has_integration_heading = False
        integration_heading_order = None
        for block in blocks:
            if block.get("type") == "heading3":
                content_lower = block.get("content", "").lower()
                if "integration apis" in content_lower or "integration" in content_lower and "apis" in content_lower:
                    has_integration_heading = True
                    integration_heading_order = block.get("order", 0)
                    break
    
        if not has_integration_heading:
            errors.append("[X] Missing heading3 '🔗 Integration APIs'")
        else:
            checks_passed.append("[C] has heading3 '🔗 Integration APIs'")
    
        # 11. Verify numberedList under Integration
        required_integration = [
            "rest api v2",
            "graphql endpoint",
            "webhook subscriptions"
        ]
    
        integration_items_found = 0
        for block in blocks:
            order = block.get("order", 0)
            if order > integration_heading_order:
                if block.get("type") == "numberedList":
                    content_lower = block.get("content", "").lower()
                    for req in required_integration:
                        if req in content_lower:
                            integration_items_found += 1
                            break
    
        if integration_items_found < 3:
            errors.append(f"[X] Integration section missing required numbered items. Found {integration_items_found}/3")
        else:
            checks_passed.append(f"[C] Integration section has required numbered items. Found {integration_items_found}/3")
    
        # 12. Verify team photo image at bottom
        team_directory_page = _find_page_by_title_direct(backend, "Team Directory")
        has_team_image = False
    
        # Check for image block near end of page
        max_order = max(b.get("order", 0) for b in blocks)
        for block in blocks:
            order = block.get("order", 0)
            if order >= max_order - 3:  # Near the end
                if block.get("type") == "image":
                    props = block.get("properties", {})
                    caption = props.get("caption", "")
                    if "product team collaborative session" in caption.lower() and "january 2024" in caption.lower():
                        has_team_image = True
                        break
    
        if not has_team_image:
            errors.append("[X] Missing team photo image with caption 'Product team collaborative session - January 2024'")
        else:
            checks_passed.append("[C] has team photo image with caption 'Product team collaborative session - January 2024'")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_agent_create_three_child_pages_under_engineering_wiki(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Task: Create three new child pages under 'Engineering Wiki'.
    
    Prompt: "Navigate to 'Engineering Wiki' page. First, create three new child pages: 'Backend Best Practices' with 🔧 icon, 'Frontend Standards' with 🎨 icon, and 'Testing Guidelines' with 🧪 icon. In each new page, add a heading_1 with the page title, then a heading_2 '📋 Checklist' followed by exactly 3 unchecked todo blocks. For Backend: 'Use dependency injection', 'Implement circuit breakers', 'Add comprehensive logging'. For Frontend: 'Follow component composition patterns', 'Implement error boundaries', 'Use semantic HTML'. For Testing: 'Maintain 80% code coverage', 'Write integration tests for APIs', 'Use snapshot testing for UI components'."
    
    Validates:
    1. Find 'Engineering Wiki' page
    2. Verify 'Backend Best Practices' page exists with 🔧 icon
    3. Verify 'Frontend Standards' page exists with 🎨 icon
    4. Verify 'Testing Guidelines' page exists with 🧪 icon
    5. Validate Backend Best Practices content
    6. Validate Frontend Standards content
    7. Validate Testing Guidelines content
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Find 'Engineering Wiki' page using direct query
    try:
        wiki_page = _find_page_by_title_direct(backend, "Engineering Wiki")
        if not wiki_page:
            errors.append("[X] Page 'Engineering Wiki' not found")
        else:
            checks_passed.append("[C] Page 'Engineering Wiki' found")
    
        wiki_id = wiki_page.get("_id")
    
        # 2. Verify 'Backend Best Practices' page exists with 🔧 icon using direct query
        backend_page = _find_page_by_title_direct(backend, "Backend Best Practices")
        if not backend_page:
            errors.append("[X] Page 'Backend Best Practices' not found")
        else:
            checks_passed.append("[C] Page 'Backend Best Practices' found")
    
        if backend_page.get("parentId") != wiki_id:
            errors.append("[X] Backend Best Practices must be a child of Engineering Wiki")
        else:
            checks_passed.append("[C] Backend Best Practices must be a child of Engineering Wiki")
    
        if backend_page.get("icon", "") != "🔧":
            errors.append(f"[X] Backend Best Practices page must have 🔧 icon. Found: '{backend_page.get('icon', '')}'")
        else:
            checks_passed.append(f"[C] Backend Best Practices page must have 🔧 icon. Found: '{backend_page.get('icon', '')}'")
    
        # 3. Verify 'Frontend Standards' page exists with 🎨 icon using direct query
        frontend_page = _find_page_by_title_direct(backend, "Frontend Standards")
        if not frontend_page:
            errors.append("[X] Page 'Frontend Standards' not found")
        else:
            checks_passed.append("[C] Page 'Frontend Standards' found")
    
        if frontend_page.get("parentId") != wiki_id:
            errors.append("[X] Frontend Standards must be a child of Engineering Wiki")
        else:
            checks_passed.append("[C] Frontend Standards must be a child of Engineering Wiki")
    
        if frontend_page.get("icon", "") != "🎨":
            errors.append(f"[X] Frontend Standards page must have 🎨 icon. Found: '{frontend_page.get('icon', '')}'")
        else:
            checks_passed.append(f"[C] Frontend Standards page must have 🎨 icon. Found: '{frontend_page.get('icon', '')}'")
    
        # 4. Verify 'Testing Guidelines' page exists with 🧪 icon using direct query
        testing_page = _find_page_by_title_direct(backend, "Testing Guidelines")
        if not testing_page:
            errors.append("[X] Page 'Testing Guidelines' not found")
        else:
            checks_passed.append("[C] Page 'Testing Guidelines' found")
    
        if testing_page.get("parentId") != wiki_id:
            errors.append("[X] Testing Guidelines must be a child of Engineering Wiki")
        else:
            checks_passed.append("[C] Testing Guidelines must be a child of Engineering Wiki")
    
        if testing_page.get("icon", "") != "🧪":
            errors.append(f"[X] Testing Guidelines page must have 🧪 icon. Found: '{testing_page.get('icon', '')}'")
        else:
            checks_passed.append(f"[C] Testing Guidelines page must have 🧪 icon. Found: '{testing_page.get('icon', '')}'")
    
        # 5. Validate Backend Best Practices content using direct query
        backend_blocks = _get_blocks_for_page_direct(backend, backend_page.get("_id"))
        backend_blocks.sort(key=lambda b: b.get("order", 0))
    
        has_backend_heading1 = False
        has_backend_checklist = False
        backend_todos = []
    
        for block in backend_blocks:
            if block.get("type") == "heading1":
                content_lower = block.get("content", "").lower()
                if "backend best practices" in content_lower:
                    has_backend_heading1 = True
            elif block.get("type") == "heading2":
                content_lower = block.get("content", "").lower()
                if "checklist" in content_lower:
                    has_backend_checklist = True
            elif block.get("type") == "todo":
                props = block.get("properties", {})
                if not props.get("checked", False):
                    backend_todos.append(block.get("content", "").lower())
    
        if not has_backend_heading1:
            errors.append("[X] Backend Best Practices missing heading1 with page title")
        else:
            checks_passed.append("[C] Backend Best Practices has heading1 with page title")
    
        if not has_backend_checklist:
            errors.append("[X] Backend Best Practices missing heading2 '📋 Checklist'")
        else:
            checks_passed.append("[C] Backend Best Practices has heading2 '📋 Checklist'")
    
        required_backend_todos = [
            "use dependency injection",
            "implement circuit breakers",
            "add comprehensive logging"
        ]
    
        backend_todos_found = 0
        for req in required_backend_todos:
            for todo in backend_todos:
                if req in todo:
                    backend_todos_found += 1
                    break
    
        if backend_todos_found < 3:
            errors.append(f"[X] Backend Best Practices missing required todos. Found {backend_todos_found}/3")
        else:
            checks_passed.append(f"[C] Backend Best Practices has required todos. Found {backend_todos_found}/3")
    
        # 6. Validate Frontend Standards content using direct query
        frontend_blocks = _get_blocks_for_page_direct(backend, frontend_page.get("_id"))
        frontend_blocks.sort(key=lambda b: b.get("order", 0))
    
        has_frontend_heading1 = False
        has_frontend_checklist = False
        frontend_todos = []
    
        for block in frontend_blocks:
            if block.get("type") == "heading1":
                content_lower = block.get("content", "").lower()
                if "frontend standards" in content_lower:
                    has_frontend_heading1 = True
            elif block.get("type") == "heading2":
                content_lower = block.get("content", "").lower()
                if "checklist" in content_lower:
                    has_frontend_checklist = True
            elif block.get("type") == "todo":
                props = block.get("properties", {})
                if not props.get("checked", False):
                    frontend_todos.append(block.get("content", "").lower())
    
        if not has_frontend_heading1:
            errors.append("[X] Frontend Standards missing heading1 with page title")
        else:
            checks_passed.append("[C] Frontend Standards has heading1 with page title")
    
        if not has_frontend_checklist:
            errors.append("[X] Frontend Standards missing heading2 '📋 Checklist'")
        else:
            checks_passed.append("[C] Frontend Standards has heading2 '📋 Checklist'")
    
        required_frontend_todos = [
            "follow component composition patterns",
            "implement error boundaries",
            "use semantic html"
        ]
    
        frontend_todos_found = 0
        for req in required_frontend_todos:
            for todo in frontend_todos:
                if req in todo:
                    frontend_todos_found += 1
                    break
    
        if frontend_todos_found < 3:
            errors.append(f"[X] Frontend Standards missing required todos. Found {frontend_todos_found}/3")
        else:
            checks_passed.append(f"[C] Frontend Standards has required todos. Found {frontend_todos_found}/3")
    
        # 7. Validate Testing Guidelines content using direct query
        testing_blocks = _get_blocks_for_page_direct(backend, testing_page.get("_id"))
        testing_blocks.sort(key=lambda b: b.get("order", 0))
    
        has_testing_heading1 = False
        has_testing_checklist = False
        testing_todos = []
    
        for block in testing_blocks:
            if block.get("type") == "heading1":
                content_lower = block.get("content", "").lower()
                if "testing guidelines" in content_lower:
                    has_testing_heading1 = True
            elif block.get("type") == "heading2":
                content_lower = block.get("content", "").lower()
                if "checklist" in content_lower:
                    has_testing_checklist = True
            elif block.get("type") == "todo":
                props = block.get("properties", {})
                if not props.get("checked", False):
                    testing_todos.append(block.get("content", "").lower())
    
        if not has_testing_heading1:
            errors.append("[X] Testing Guidelines missing heading1 with page title")
        else:
            checks_passed.append("[C] Testing Guidelines has heading1 with page title")
    
        if not has_testing_checklist:
            errors.append("[X] Testing Guidelines missing heading2 '📋 Checklist'")
        else:
            checks_passed.append("[C] Testing Guidelines has heading2 '📋 Checklist'")
    
        required_testing_todos = [
            "maintain 80% code coverage",
            "write integration tests for apis",
            "use snapshot testing for ui components"
        ]
    
        testing_todos_found = 0
        for req in required_testing_todos:
            for todo in testing_todos:
                if req in todo:
                    testing_todos_found += 1
                    break
    
        if testing_todos_found < 3:
            errors.append(f"[X] Testing Guidelines missing required todos. Found {testing_todos_found}/3")
        else:
            checks_passed.append(f"[C] Testing Guidelines has required todos. Found {testing_todos_found}/3")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_agent_swap_overview_and_user_stories_sections(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Task: On the 'Comprehensive Product Requirements Document' page, swap Overview and User Stories sections.
    
    Prompt: "On the 'Comprehensive Product Requirements Document' page: First, swap the positions of the 'Overview' and 'User Stories' sections entirely, maintaining all sub-sections and content within each. Then within the 'Overview' section (now in its new position), add a new heading_3 'Overview - Critical Updates' immediately after 'Overview - Part 3' but before the start of what was originally the 'User Stories' content. Under this new heading, add a callout with red_background, icon '🚨', containing exact text 'IMPORTANT: All requirements in this section have been approved by stakeholders as of [today's date]'. Finally, at the very beginning of the page (after the main title but before any other content), insert a quote block with text 'Excellence in documentation leads to excellence in execution.'"
    
    Validates:
    1. Find 'Comprehensive Product Requirements Document' page
    2. Verify sections are swapped
    3. Verify 'Overview - Critical Updates' heading3 exists
    4. Verify red callout with alert icon
    5. Verify quote block at beginning
    6. Verify Overview subsections preserved
    7. Verify User Stories content preserved
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Find 'Comprehensive Product Requirements Document' page using direct query
    try:
        prd_page = _find_page_by_title_direct(backend, "Comprehensive Product Requirements Document")
        if not prd_page:
            errors.append("[X] Page 'Comprehensive Product Requirements Document' not found")
        else:
            checks_passed.append("[C] Page 'Comprehensive Product Requirements Document' found")
    
        page_id = prd_page.get("_id")
        if not page_id:
            errors.append("[X] Comprehensive Product Requirements Document page has no _id")
        else:
            checks_passed.append("[C] Comprehensive Product Requirements Document page has _id")
    
        # Get all blocks for the page using direct query
        blocks = _get_blocks_for_page_direct(backend, page_id)
        if not blocks:
            errors.append("[X] Page has no content blocks")
        else:
            checks_passed.append("[C] Page has content blocks")
    
        blocks.sort(key=lambda b: b.get("order", 0))
    
        # 2. Verify sections are swapped
        overview_order = None
        user_stories_order = None
    
        for block in blocks:
            if block.get("type") == "heading2":
                content_lower = block.get("content", "").lower()
                if content_lower == "overview" or content_lower.strip() == "overview":
                    overview_order = block.get("order", 0)
                elif "user stories" in content_lower:
                    user_stories_order = block.get("order", 0)
    
        if user_stories_order is None:
            errors.append("[X] Heading 'User Stories' not found")
        else:
            checks_passed.append("[C] Heading 'User Stories' found")
    
        if overview_order is None:
            errors.append("[X] Heading 'Overview' not found")
        else:
            checks_passed.append("[C] Heading 'Overview' found")
    
        if user_stories_order >= overview_order:
            errors.append(f"[X] Sections not swapped: User Stories (order {user_stories_order}) should come BEFORE Overview (order {overview_order})")
        else:
            checks_passed.append(f"[C] Sections swapped: User Stories (order {user_stories_order}) should come BEFORE Overview (order {overview_order})")
    
        # 3. Verify 'Overview - Critical Updates' heading3 exists
        has_critical_updates = False
        critical_updates_order = None
        overview_part3_order = None
    
        # Find Overview - Part 3 first
        for block in blocks:
            if block.get("type") == "heading3":
                content_lower = block.get("content", "").lower()
                if "overview - part 3" in content_lower or "overview part 3" in content_lower:
                    overview_part3_order = block.get("order", 0)
                elif "overview - critical updates" in content_lower:
                    has_critical_updates = True
                    critical_updates_order = block.get("order", 0)
    
        if overview_part3_order is None:
            errors.append("[X] Heading 'Overview - Part 3' not found")
        else:
            checks_passed.append("[C] Heading 'Overview - Part 3' found")
    
        if not has_critical_updates:
            errors.append("[X] Heading3 'Overview - Critical Updates' not found")
        else:
            checks_passed.append("[C] Heading3 'Overview - Critical Updates' found")
    
        if critical_updates_order <= overview_part3_order:
            errors.append("[X] Overview - Critical Updates must appear AFTER Overview - Part 3")
        else:
            checks_passed.append("[C] Overview - Critical Updates must appear AFTER Overview - Part 3")
    
        # 4. Verify red callout with alert icon
        has_red_callout = False
        for block in blocks:
            order = block.get("order", 0)
            if order > critical_updates_order:
                if block.get("type") == "callout":
                    props = block.get("properties", {})
                    bg_color = props.get("backgroundColor", "").lower()
                    icon = props.get("icon", "")
                    content = block.get("content", "")
                    content_lower = content.lower()
                
                    if "red" in bg_color and "🚨" in icon:
                        if "important: all requirements in this section have been approved by stakeholders" in content_lower:
                            # Check for date (accept various formats)
                            if any(date_indicator in content_lower for date_indicator in ["as of", "2024", "2025", "2026", "january", "february", "march"]):
                                has_red_callout = True
                                break
    
        if not has_red_callout:
            errors.append("[X] Red callout with 🚨 icon containing approval text and date not found after Overview - Critical Updates")
        else:
            checks_passed.append("[C] Red callout with 🚨 icon containing approval text and date found after Overview - Critical Updates")
    
        # 5. Verify quote block at beginning
        heading1_order = None
        quote_order = None
    
        for block in blocks:
            if block.get("type") == "heading1":
                heading1_order = block.get("order", 0)
            elif block.get("type") == "quote":
                content_lower = block.get("content", "").lower()
                if "excellence in documentation leads to excellence in execution" in content_lower:
                    quote_order = block.get("order", 0)
    
        if heading1_order is None:
            errors.append("[X] No heading1 found on page")
        else:
            checks_passed.append("[C] heading1 found on page")
    
        if quote_order is None:
            errors.append("[X] Quote block with 'Excellence in documentation leads to excellence in execution.' not found")
        else:
            checks_passed.append("[C] Quote block with 'Excellence in documentation leads to excellence in execution.' found")
    
        if quote_order <= heading1_order:
            errors.append("[X] Quote block should appear AFTER main title (heading1)")
        else:
            checks_passed.append("[C] Quote block should appear AFTER main title (heading1)")
    
        # Check quote appears before other significant content
        if quote_order > user_stories_order:
            errors.append("[X] Quote block should appear at the beginning of the page, before User Stories section")
        else:
            checks_passed.append("[C] Quote block should appear at the beginning of the page, before User Stories section")
    
        # 6. Verify Overview subsections preserved
        overview_parts = 0
        for block in blocks:
            if block.get("type") == "heading3":
                content_lower = block.get("content", "").lower()
                if "overview - part" in content_lower:
                    overview_parts += 1
    
        if overview_parts < 3:
            errors.append(f"[X] Overview section should have 3 subsections (Part 1, 2, 3). Found: {overview_parts}")
        else:
            checks_passed.append(f"[C] Overview section should have 3 subsections (Part 1, 2, 3). Found: {overview_parts}")
    
        # 7. Verify User Stories content preserved (check for User Stories subsections)
        user_stories_parts = 0
        in_user_stories = False
        for block in blocks:
            if block.get("type") == "heading2":
                content_lower = block.get("content", "").lower()
                if "user stories" in content_lower:
                    in_user_stories = True
                elif content_lower == "overview" or content_lower.strip() == "overview":
                    in_user_stories = False
            elif block.get("type") == "heading3" and in_user_stories:
                content_lower = block.get("content", "").lower()
                if "part" in content_lower:
                    user_stories_parts += 1
    
        # User Stories should have some content (at least subsections)
        if user_stories_parts == 0:
            errors.append("[X] User Stories section content not preserved after swap")
        else:
            checks_passed.append("[C] User Stories section content preserved after swap")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_agent_reorganize_design_system_page(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Task: Reorganize Design System page by moving child pages and adding new content.
    
    Prompt: "Navigate to 'Design System' page (with icon 🎨). First, move all existing child pages ('Color Palette', 'Typography', 'Components') to a new sub-page called '📦 Core Design Assets'. Then in the main Design System page, add heading_1 '🎨 Design System Hub', followed by heading_2 '🚀 Latest Updates' with a callout (yellow_background, icon '📅') containing: 'Last review: [today's date] | Next review scheduled: [30 days from today]'. Add heading_2 '📐 Design Principles' with a numberedList: '1. Consistency across all products', '2. Accessibility as a priority', '3. Mobile-first approach', '4. Performance optimization', '5. Scalable component architecture'. Finally, add a bookmark to the moved 'Core Design Assets' page with caption 'Access all design resources'."
    
    Validates:
    1. Find 'Design System' page with 🎨 icon
    2. Verify 'Core Design Assets' sub-page exists
    3. Verify original child pages moved
    4. Verify heading1 '🎨 Design System Hub'
    5. Verify heading2 '🚀 Latest Updates'
    6. Verify yellow callout with dates
    7. Verify heading2 '📐 Design Principles'
    8. Verify numberedList with 5 principles
    9. Verify bookmark to Core Design Assets
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Find 'Design System' page with 🎨 icon using direct query
    try:
        design_system_pages = _find_pages_by_title_direct(backend, "Design System")
        if not design_system_pages:
            errors.append("[X] Page 'Design System' not found")
        else:
            checks_passed.append("[C] Page 'Design System' found")
    
        # Filter to pages with 🎨 icon
        design_system_pages = [p for p in design_system_pages if p.get("icon", "") == "🎨"]
        if not design_system_pages:
            errors.append("[X] Design System page with 🎨 icon not found")
        else:
            checks_passed.append("[C] Design System page with 🎨 icon found")
    
        # Find the correct Design System page - prefer workspace-2 which has the original child pages
        # The child pages (Color Palette, Typography, Components) are in workspace-2
        design_system_page = None
    
        # First priority: find Design System in workspace-2
        for ds_page in design_system_pages:
            if ds_page.get("workspaceId") == "workspace-2":
                design_system_page = ds_page
                break
    
        # Second priority: find Design System that is parent of Core Design Assets
        if not design_system_page:
            core_assets_page_check = _find_page_by_title_direct(backend, "Core Design Assets")
            if core_assets_page_check:
                core_parent_id = core_assets_page_check.get("parentId")
                for ds_page in design_system_pages:
                    if ds_page.get("_id") == core_parent_id:
                        design_system_page = ds_page
                        break
    
        # Last resort: use first Design System with 🎨 icon
        if not design_system_page:
            design_system_page = design_system_pages[0]
    
        design_system_id = design_system_page.get("_id")
    
        # 2. Verify 'Core Design Assets' sub-page exists using direct query
        core_assets_page = _find_page_by_title_direct(backend, "Core Design Assets")
        if not core_assets_page:
            errors.append("[X] Page 'Core Design Assets' not found")
        else:
            checks_passed.append("[C] Page 'Core Design Assets' found")
    
        if core_assets_page.get("parentId") != design_system_id:
            errors.append(f"[X] Core Design Assets must be a child of Design System. Found parentId: {core_assets_page.get('parentId')}, expected: {design_system_id}")
        else:
            checks_passed.append(f"[C] Core Design Assets must be a child of Design System. Found parentId: {core_assets_page.get('parentId')}, expected: {design_system_id}")
    
        core_assets_id = core_assets_page.get("_id")
    
        # 3. Verify original child pages moved using direct query
        original_pages = ["Color Palette", "Typography", "Components"]
        for page_title in original_pages:
            page = _find_page_by_title_direct(backend, page_title)
            if not page:
                errors.append(f"[X] Page '{page_title}' not found")
            else:
                checks_passed.append(f"[C] Page '{page_title}' found")
        
            if page.get("parentId") != core_assets_id:
                errors.append(f"[X] Page '{page_title}' must be a child of Core Design Assets. Found parentId: {page.get('parentId')}")
            else:
                checks_passed.append(f"[C] Page '{page_title}' must be a child of Core Design Assets. Found parentId: {page.get('parentId')}")
    
        # Get all blocks for Design System page using direct query
        blocks = _get_blocks_for_page_direct(backend, design_system_id)
        if not blocks:
            errors.append("[X] Design System page has no content blocks")
        else:
            checks_passed.append("[C] Design System page has content blocks")
    
        blocks.sort(key=lambda b: b.get("order", 0))
    
        # 4. Verify heading1 '🎨 Design System Hub'
        has_hub_heading = False
        for block in blocks:
            if block.get("type") == "heading1":
                content_lower = block.get("content", "").lower()
                if "design system hub" in content_lower:
                    has_hub_heading = True
                    break
    
        if not has_hub_heading:
            errors.append("[X] Missing heading1 '🎨 Design System Hub'")
        else:
            checks_passed.append("[C] has heading1 '🎨 Design System Hub'")
    
        # 5. Verify heading2 '🚀 Latest Updates'
        has_updates_heading = False
        updates_heading_order = None
        for block in blocks:
            if block.get("type") == "heading2":
                content_lower = block.get("content", "").lower()
                if "latest updates" in content_lower:
                    has_updates_heading = True
                    updates_heading_order = block.get("order", 0)
                    break
    
        if not has_updates_heading:
            errors.append("[X] Missing heading2 '🚀 Latest Updates'")
        else:
            checks_passed.append("[C] has heading2 '🚀 Latest Updates'")
    
        # 6. Verify yellow callout with dates
        has_yellow_callout = False
        for block in blocks:
            order = block.get("order", 0)
            if order > updates_heading_order:
                if block.get("type") == "callout":
                    props = block.get("properties", {})
                    bg_color = props.get("backgroundColor", "").lower()
                    icon = props.get("icon", "")
                    content = block.get("content", "")
                    content_lower = content.lower()
                
                    if "yellow" in bg_color and "📅" in icon:
                        if "last review" in content_lower and "next review scheduled" in content_lower:
                            # Check for date indicators
                            if any(date_indicator in content_lower for date_indicator in ["2024", "2025", "2026", "january", "february", "march", "april", "may", "june", "30 days"]):
                                has_yellow_callout = True
                                break
    
        if not has_yellow_callout:
            errors.append("[X] Yellow callout with 📅 icon containing review dates not found")
        else:
            checks_passed.append("[C] Yellow callout with 📅 icon containing review dates found")
    
        # 7. Verify heading2 '📐 Design Principles'
        has_principles_heading = False
        principles_heading_order = None
        for block in blocks:
            if block.get("type") == "heading2":
                content_lower = block.get("content", "").lower()
                if "design principles" in content_lower:
                    has_principles_heading = True
                    principles_heading_order = block.get("order", 0)
                    break
    
        if not has_principles_heading:
            errors.append("[X] Missing heading2 '📐 Design Principles'")
        else:
            checks_passed.append("[C] has heading2 '📐 Design Principles'")
    
        # 8. Verify numberedList with 5 principles
        required_principles = [
            "consistency across all products",
            "accessibility as a priority",
            "mobile-first approach",
            "performance optimization",
            "scalable component architecture"
        ]
    
        principles_found = 0
        for block in blocks:
            order = block.get("order", 0)
            if order > principles_heading_order:
                if block.get("type") == "numberedList":
                    content_lower = block.get("content", "").lower()
                    for req in required_principles:
                        if req in content_lower:
                            principles_found += 1
                            break
    
        if principles_found < 5:
            errors.append(f"[X] Design Principles section missing required items. Found {principles_found}/5")
        else:
            checks_passed.append(f"[C] Design Principles section has required items. Found {principles_found}/5")
    
        # 9. Verify bookmark to Core Design Assets
        has_bookmark = False
        for block in blocks:
            if block.get("type") == "bookmark":
                props = block.get("properties", {})
                url = props.get("url", "")
                caption = props.get("caption", "")
            
                # Check if bookmark links to Core Design Assets (could be page ID or title in URL)
                if core_assets_id in url or "core design assets" in url.lower():
                    if "access all design resources" in caption.lower():
                        has_bookmark = True
                        break
    
        if not has_bookmark:
            errors.append("[X] Bookmark to Core Design Assets with caption 'Access all design resources' not found")
        else:
            checks_passed.append("[C] Bookmark to Core Design Assets with caption 'Access all design resources' found")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_agent_add_meeting_analytics_to_sprint_planning(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Task: In the 'Sprint Planning - Jan 15' page, add meeting analytics.
    
    Prompt: "In the 'Sprint Planning - January 15, 2024' page, add sophisticated meeting analytics. After the 'Action Items' section, before any existing to-dos, insert heading_3 '⏱️ Time Allocation'. Add a callout with gray_background and '📊' icon containing: 'Meeting duration: 90 minutes'. Below, add a numbered list: '1. Attendee introductions: 5 minutes', '2. Sprint goal discussion: 30 minutes', '3. Task breakdown: 40 minutes', '4. Action item assignment: 15 minutes'. Then find all to-do blocks on the page, and add a new paragraph after the numbered list: 'Action items assigned: [count] total, [checked count] completed ([percentage]%)'. The formatting must exactly match the existing page style."
    
    Validates:
    1. Find 'Sprint Planning - Jan 15' page (task instructions say "Sprint Planning - January 15, 2024")
    2. Locate 'Action Items' section
    3. Verify heading3 '⏱️ Time Allocation'
    4. Verify gray callout with meeting duration
    5. Verify numberedList with 4 time items
    6. Count all todo blocks on page
    7. Verify paragraph with action item counts
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Find 'Sprint Planning - Jan 15' page using direct query
    try:
        sprint_page = _find_page_by_title_direct(backend, "Sprint Planning - Jan 15")
        if not sprint_page:
            # Try alternative title format
            sprint_page = _find_page_by_title_direct(backend, "Sprint Planning - January 15, 2024")
            if not sprint_page:
                errors.append("[X] Page 'Sprint Planning - Jan 15' not found")
            else:
                checks_passed.append("[C] Page 'Sprint Planning - Jan 15' found")
    
        page_id = sprint_page.get("_id")
        if not page_id:
            errors.append("[X] Sprint Planning page has no _id")
        else:
            checks_passed.append("[C] Sprint Planning page has _id")
    
        # Get all blocks for the page using direct query
        blocks = _get_blocks_for_page_direct(backend, page_id)
        if not blocks:
            errors.append("[X] Sprint Planning page has no content blocks")
        else:
            checks_passed.append("[C] Sprint Planning page has content blocks")
    
        blocks.sort(key=lambda b: b.get("order", 0))
    
        # 2. Locate 'Action Items' section
        action_items_order = None
        for block in blocks:
            if block.get("type") == "heading2":
                content_lower = block.get("content", "").lower()
                if "action items" in content_lower:
                    action_items_order = block.get("order", 0)
                    break
    
        if action_items_order is None:
            errors.append("[X] Heading 'Action Items' not found")
        else:
            checks_passed.append("[C] Heading 'Action Items' found")
    
        # 3. Verify heading3 '⏱️ Time Allocation'
        has_time_allocation = False
        time_allocation_order = None
        for block in blocks:
            order = block.get("order", 0)
            if order > action_items_order:
                if block.get("type") == "heading3":
                    content_lower = block.get("content", "").lower()
                    if "time allocation" in content_lower:
                        has_time_allocation = True
                        time_allocation_order = order
                        break
    
        if not has_time_allocation:
            errors.append("[X] Heading3 '⏱️ Time Allocation' not found after Action Items")
        else:
            checks_passed.append("[C] Heading3 '⏱️ Time Allocation' found after Action Items")
    
        # 4. Verify gray callout with meeting duration
        has_gray_callout = False
        callout_order = None
        for block in blocks:
            order = block.get("order", 0)
            if order > time_allocation_order:
                if block.get("type") == "callout":
                    props = block.get("properties", {})
                    bg_color = props.get("backgroundColor", "").lower()
                    icon = props.get("icon", "")
                    content = block.get("content", "")
                    content_lower = content.lower()
                
                    if "gray" in bg_color and "📊" in icon:
                        if "meeting duration: 90 minutes" in content_lower:
                            has_gray_callout = True
                            callout_order = order
                            break
    
        if not has_gray_callout:
            errors.append("[X] Gray callout with 📊 icon containing 'Meeting duration: 90 minutes' not found")
        else:
            checks_passed.append("[C] Gray callout with 📊 icon containing 'Meeting duration: 90 minutes' found")
    
        # 5. Verify numberedList with 4 time items
        required_time_items = [
            "attendee introductions: 5 minutes",
            "sprint goal discussion: 30 minutes",
            "task breakdown: 40 minutes",
            "action item assignment: 15 minutes"
        ]
    
        time_items_found = 0
        numbered_list_order = None
        for block in blocks:
            order = block.get("order", 0)
            if order > callout_order:
                if block.get("type") == "numberedList":
                    numbered_list_order = order
                    content_lower = block.get("content", "").lower()
                    for req in required_time_items:
                        if req in content_lower:
                            time_items_found += 1
                            break
    
        if time_items_found < 4:
            errors.append(f"[X] Numbered list missing required time items. Found {time_items_found}/4")
        else:
            checks_passed.append(f"[C] Numbered list has required time items. Found {time_items_found}/4")
    
        # 6. Count all todo blocks on page
        all_todos = [b for b in blocks if b.get("type") == "todo"]
        total_todos = len(all_todos)
        checked_todos = sum(1 for t in all_todos if t.get("properties", {}).get("checked", False))
        completion_percent = int((checked_todos / total_todos * 100)) if total_todos > 0 else 0
    
        # 7. Verify paragraph with action item counts
        has_count_paragraph = False
        if numbered_list_order is not None:
            for block in blocks:
                order = block.get("order", 0)
                if order > numbered_list_order:
                    if block.get("type") == "paragraph":
                        content = block.get("content", "")
                        content_lower = content.lower()
                    
                        if "action items assigned" in content_lower:
                            if str(total_todos) in content and "total" in content_lower:
                                if str(checked_todos) in content and "completed" in content_lower:
                                    if f"{completion_percent}%" in content or str(completion_percent) in content:
                                        has_count_paragraph = True
                                        break
    
        if not has_count_paragraph:
            errors.append(f"[X] Paragraph with action item counts not found. Expected: {total_todos} total, {checked_todos} completed ({completion_percent}%)")
        else:
            checks_passed.append(f"[C] Paragraph with action item counts found. Expected: {total_todos} total, {checked_todos} completed ({completion_percent}%)")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_agent_reorganize_project_guidelines_callouts_2(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Task: On the 'Project Guidelines & Best Practices' page, reorganize callout blocks.
    
    Prompt: "On the 'Project Guidelines & Best Practices' page, perform a complex reorganization. First, identify all callout blocks with yellow_background (💡 Tips). Create a new heading_2 '💡 Quick Tips Reference' immediately after the main page heading. Move ALL yellow background callouts to appear directly under this new heading, maintaining their original order. Then, find all red_background callouts (🚨 Critical) and move them to appear immediately after the yellow callouts section. Add a divider block between the yellow and red callout groups. Finally, at the end of the reorganized tips section (after all moved callouts), add a paragraph with italic text 'Tips reorganized on [today's date] - Yellow tips: [X], Critical warnings: [Y]' where X and Y are the counts."
    
    Validates:
    1. Find 'Project Guidelines & Best Practices' page
    2. Locate main page heading
    3. Verify heading2 '💡 Quick Tips Reference'
    4. Count and verify yellow callouts grouped
    5. Verify divider between yellow and red callouts
    6. Count and verify red callouts grouped
    7. Verify italic summary paragraph
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Find 'Project Guidelines & Best Practices' page using direct query
    try:
        guidelines_page = _find_page_by_title_direct(backend, "Project Guidelines & Best Practices")
        if not guidelines_page:
            errors.append("[X] Page 'Project Guidelines & Best Practices' not found")
        else:
            checks_passed.append("[C] Page 'Project Guidelines & Best Practices' found")
    
        page_id = guidelines_page.get("_id")
        if not page_id:
            errors.append("[X] Project Guidelines & Best Practices page has no _id")
        else:
            checks_passed.append("[C] Project Guidelines & Best Practices page has _id")
    
        # Get all blocks for the page using direct query
        blocks = _get_blocks_for_page_direct(backend, page_id)
        if not blocks:
            errors.append("[X] Page has no content blocks")
        else:
            checks_passed.append("[C] Page has content blocks")
    
        blocks.sort(key=lambda b: b.get("order", 0))
    
        # 2. Locate main page heading
        heading1_order = None
        for block in blocks:
            if block.get("type") == "heading1":
                heading1_order = block.get("order", 0)
                break
    
        if heading1_order is None:
            errors.append("[X] Main page heading (heading1) not found")
        else:
            checks_passed.append("[C] Main page heading (heading1) found")
    
        # 3. Verify heading2 '💡 Quick Tips Reference'
        has_tips_heading = False
        tips_heading_order = None
        for block in blocks:
            order = block.get("order", 0)
            if order > heading1_order:
                if block.get("type") == "heading2":
                    content_lower = block.get("content", "").lower()
                    if "quick tips reference" in content_lower:
                        has_tips_heading = True
                        tips_heading_order = order
                        break
    
        if not has_tips_heading:
            errors.append("[X] Missing heading2 '💡 Quick Tips Reference' after main heading")
        else:
            checks_passed.append("[C] has heading2 '💡 Quick Tips Reference' after main heading")
    
        # Count callouts by type
        yellow_callouts = []
        red_callouts = []
        divider_order = None
    
        for block in blocks:
            if block.get("type") == "callout":
                props = block.get("properties", {})
                bg_color = props.get("backgroundColor", "").lower()
                icon = props.get("icon", "")
                order = block.get("order", 0)
            
                if "yellow" in bg_color:
                    yellow_callouts.append((order, block))
                elif "red" in bg_color:
                    red_callouts.append((order, block))
            elif block.get("type") == "divider":
                divider_order = block.get("order", 0)
    
        # 4. Count and verify yellow callouts grouped
        if len(yellow_callouts) == 0:
            errors.append("[X] No yellow callouts found on page")
        else:
            checks_passed.append("[C] yellow callouts found on page")
    
        # Verify all yellow callouts appear after tips heading
        for order, _ in yellow_callouts:
            if order <= tips_heading_order:
                errors.append("[X] Yellow callouts must appear after Quick Tips Reference heading")
            else:
                checks_passed.append("[C] Yellow callouts must appear after Quick Tips Reference heading")
    
        # 5. Verify divider between yellow and red callouts
        if divider_order is None:
            errors.append("[X] Divider not found between yellow and red callouts")
        else:
            checks_passed.append("[C] Divider found between yellow and red callouts")
    
        # Verify divider is after yellow callouts but before red callouts
        max_yellow_order = max(order for order, _ in yellow_callouts) if yellow_callouts else tips_heading_order
        min_red_order = min(order for order, _ in red_callouts) if red_callouts else float('inf')
    
        if not (max_yellow_order < divider_order < min_red_order):
            errors.append("[X] Divider must appear after yellow callouts but before red callouts")
        else:
            checks_passed.append("[C] Divider must appear after yellow callouts but before red callouts")
    
        # 6. Count and verify red callouts grouped
        if len(red_callouts) == 0:
            errors.append("[X] No red callouts found on page")
        else:
            checks_passed.append("[C] red callouts found on page")
    
        # Verify all red callouts appear after divider
        for order, _ in red_callouts:
            if order <= divider_order:
                errors.append("[X] Red callouts must appear after divider")
            else:
                checks_passed.append("[C] Red callouts must appear after divider")
    
        # 7. Verify italic summary paragraph
        has_summary_paragraph = False
        max_callout_order = max([max(order for order, _ in yellow_callouts) if yellow_callouts else 0,
                                max(order for order, _ in red_callouts) if red_callouts else 0])
    
        for block in blocks:
            order = block.get("order", 0)
            if order > max_callout_order:
                if block.get("type") == "paragraph":
                    content = block.get("content", "")
                    content_lower = content.lower()
                    props = block.get("properties", {})
                
                    if "tips reorganized on" in content_lower:
                        # Check for italic formatting
                        if _check_text_is_italic(content, props) or "*" in content:
                            # Check for counts
                            if f"yellow tips: {len(yellow_callouts)}" in content_lower or f"yellow tips: {len(yellow_callouts)}" in content:
                                if f"critical warnings: {len(red_callouts)}" in content_lower or f"critical warnings: {len(red_callouts)}" in content:
                                    # Check for date
                                    if any(date_indicator in content_lower for date_indicator in ["2024", "2025", "2026", "january", "february", "march"]):
                                        has_summary_paragraph = True
                                        break
    
        if not has_summary_paragraph:
            errors.append(f"[X] Italic summary paragraph not found with correct counts. Expected: Yellow tips: {len(yellow_callouts)}, Critical warnings: {len(red_callouts)}")
        else:
            checks_passed.append(f"[C] Italic summary paragraph found with correct counts. Expected: Yellow tips: {len(yellow_callouts)}, Critical warnings: {len(red_callouts)}")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_agent_project_roadmap_reorganization(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Task: Reorganize Project Roadmap with quarterly summary and Q3 Goals sub-page.
    
    Prompt: "Perform a complex reorganization of the 'Project Roadmap' page and its sub-pages. First, on the main Project Roadmap page, add a new heading2 '📅 Quarterly Summary' immediately after the main description but before the quote. Under this heading, fetch key data from Q1 and Q2 Goals sub-pages and create two callout blocks: First callout with green_background if Q1 has >50% todos checked (otherwise yellow_background) showing 'Q1 2024: [X]% complete - [first unchecked todo text or \"All tasks completed\"]'. Second callout with similar logic for Q2. Then create a new sub-page under Project Roadmap titled 'Q3 Goals' with heading2 'Q3 2024 Objectives' and three unchecked todos: 'Scale infrastructure for 10x growth', 'Launch enterprise features', 'Achieve SOC2 compliance'."
    
    Validates:
    1. Find 'Project Roadmap' page
    2. heading_2 '📅 Quarterly Summary' exists after description, before quote
    3. Q1 callout with correct color (green >50%, yellow otherwise)
    4. Q1 callout shows correct percentage and first unchecked todo
    5. Q2 callout with correct color based on completion
    6. Q2 callout shows correct percentage and first unchecked todo
    7. New page 'Q3 Goals' exists as child of Project Roadmap
    8. Q3 Goals has heading_2 and 3 unchecked todos with exact text
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Find 'Project Roadmap' page using direct query
    try:
        roadmap_page = _find_page_by_title_direct(backend, "Project Roadmap")
        if not roadmap_page:
            errors.append("[X] Page 'Project Roadmap' not found")
        else:
            checks_passed.append("[C] Page 'Project Roadmap' found")
    
        roadmap_id = roadmap_page.get("_id")
        if not roadmap_id:
            errors.append("[X] Project Roadmap page has no _id")
        else:
            checks_passed.append("[C] Project Roadmap page has _id")
    
        # Get Q1 and Q2 Goals pages using direct query
        q1_page = _find_page_by_title_direct(backend, "Q1 Goals")
        q2_page = _find_page_by_title_direct(backend, "Q2 Goals")
    
        # Calculate Q1 completion stats
        q1_percent = 0
        q1_first_unchecked = "All tasks completed"
        if q1_page:
            q1_id = q1_page.get("_id")
            q1_blocks = _get_blocks_for_page_direct(backend, q1_id)
            q1_todos = [b for b in q1_blocks if b.get("type") == "todo"]
            q1_total = len(q1_todos)
            q1_checked = sum(1 for t in q1_todos if t.get("properties", {}).get("checked", False))
            q1_percent = int((q1_checked / q1_total * 100)) if q1_total > 0 else 0
        
            # Find first unchecked todo
            for t in q1_todos:
                if not t.get("properties", {}).get("checked", False):
                    q1_first_unchecked = t.get("content", "Unknown task")
                    break
    
        # Calculate Q2 completion stats
        q2_percent = 0
        q2_first_unchecked = "All tasks completed"
        if q2_page:
            q2_id = q2_page.get("_id")
            q2_blocks = _get_blocks_for_page_direct(backend, q2_id)
            q2_todos = [b for b in q2_blocks if b.get("type") == "todo"]
            q2_total = len(q2_todos)
            q2_checked = sum(1 for t in q2_todos if t.get("properties", {}).get("checked", False))
            q2_percent = int((q2_checked / q2_total * 100)) if q2_total > 0 else 0
        
            # Find first unchecked todo
            for t in q2_todos:
                if not t.get("properties", {}).get("checked", False):
                    q2_first_unchecked = t.get("content", "Unknown task")
                    break
    
        # Get roadmap page blocks using direct query
        blocks = _get_blocks_for_page_direct(backend, roadmap_id)
        if not blocks:
            errors.append("[X] Project Roadmap page has no content blocks")
        else:
            checks_passed.append("[C] Project Roadmap page has content blocks")
    
        blocks.sort(key=lambda b: b.get("order", 0))
    
        # Find quote order
        quote_order = None
        for block in blocks:
            if block.get("type") == "quote":
                quote_order = block.get("order", 0)
                break
    
        # 2. Verify heading_2 '📅 Quarterly Summary' exists before quote
        quarterly_summary_found = False
        quarterly_summary_order = None
        for block in blocks:
            if block.get("type") == "heading2":
                content = block.get("content", "")
                if "quarterly summary" in content.lower():
                    quarterly_summary_found = True
                    quarterly_summary_order = block.get("order", 0)
                    break
    
        if not quarterly_summary_found:
            errors.append("[X] heading_2 '📅 Quarterly Summary' not found")
        else:
            checks_passed.append("[C] heading_2 '📅 Quarterly Summary' found")
    
        if quote_order is not None and quarterly_summary_order >= quote_order:
            errors.append("[X] Quarterly Summary section not positioned before the quote block")
        else:
            checks_passed.append("[C] Quarterly Summary section positioned before the quote block")
    
        # 3 & 4. Verify Q1 callout with correct color and content
        q1_expected_color = "green" if q1_percent > 50 else "yellow"
        q1_callout_found = False
    
        for block in blocks:
            if block.get("type") == "callout":
                props = block.get("properties", {})
                bg_color = props.get("backgroundColor", "").lower()
                content = block.get("content", "")
                content_lower = content.lower()
            
                if "q1" in content_lower and ("2024" in content_lower or "%" in content):
                    # Verify color
                    if q1_expected_color in bg_color:
                        q1_callout_found = True
                        break
    
        if not q1_callout_found:
            errors.append(f"[X] Q1 callout with {q1_expected_color}_background not found. Q1 completion: {q1_percent}%")
        else:
            checks_passed.append(f"[C] Q1 callout with {q1_expected_color}_background found. Q1 completion: {q1_percent}%")
    
        # 5 & 6. Verify Q2 callout with correct color and content
        q2_expected_color = "green" if q2_percent > 50 else "yellow"
        q2_callout_found = False
    
        for block in blocks:
            if block.get("type") == "callout":
                props = block.get("properties", {})
                bg_color = props.get("backgroundColor", "").lower()
                content = block.get("content", "")
                content_lower = content.lower()
            
                if "q2" in content_lower and ("2024" in content_lower or "%" in content):
                    # Verify color
                    if q2_expected_color in bg_color:
                        q2_callout_found = True
                        break
    
        if not q2_callout_found:
            errors.append(f"[X] Q2 callout with {q2_expected_color}_background not found. Q2 completion: {q2_percent}%")
        else:
            checks_passed.append(f"[C] Q2 callout with {q2_expected_color}_background found. Q2 completion: {q2_percent}%")
    
        # 7. Verify Q3 Goals page exists as child of Project Roadmap
        q3_page = _find_page_by_title_direct(backend, "Q3 Goals")
        if not q3_page:
            errors.append("[X] Page 'Q3 Goals' not found")
        else:
            checks_passed.append("[C] Page 'Q3 Goals' found")
    
        q3_parent = q3_page.get("parentId")
        if q3_parent != roadmap_id:
            errors.append(f"[X] Q3 Goals is not child of Project Roadmap. Parent: {q3_parent}, expected: {roadmap_id}")
        else:
            checks_passed.append(f"[C] Q3 Goals is child of Project Roadmap. Parent: {q3_parent}, expected: {roadmap_id}")
    
        # 8. Verify Q3 Goals has heading_2 and 3 unchecked todos
        q3_id = q3_page.get("_id")
        q3_blocks = _get_blocks_for_page_direct(backend, q3_id)
    
        if not q3_blocks:
            errors.append("[X] Q3 Goals page has no content blocks")
        else:
            checks_passed.append("[C] Q3 Goals page has content blocks")
    
        # Check for heading_2
        q3_heading_found = False
        for block in q3_blocks:
            if block.get("type") == "heading2":
                content_lower = block.get("content", "").lower()
                if "q3" in content_lower and "2024" in content_lower and "objectives" in content_lower:
                    q3_heading_found = True
                    break
    
        if not q3_heading_found:
            errors.append("[X] heading_2 'Q3 2024 Objectives' not found in Q3 Goals page")
        else:
            checks_passed.append("[C] heading_2 'Q3 2024 Objectives' found in Q3 Goals page")
    
        # Check for 3 unchecked todos with specific text
        required_q3_todos = [
            "scale infrastructure",
            "enterprise features",
            "soc2"
        ]
    
        q3_todos_found = 0
        for block in q3_blocks:
            if block.get("type") == "todo":
                props = block.get("properties", {})
                is_unchecked = not props.get("checked", False)
                content_lower = block.get("content", "").lower()
            
                if is_unchecked:
                    for req in required_q3_todos:
                        if req in content_lower:
                            q3_todos_found += 1
                            break
    
        if q3_todos_found < 3:
            errors.append(f"[X] Q3 Goals page missing required unchecked todos. Found {q3_todos_found}/3")
        else:
            checks_passed.append(f"[C] Q3 Goals page has required unchecked todos. Found {q3_todos_found}/3")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_agent_engineering_standards(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Task: Create Engineering Standards page as child of Engineering Wiki.
    
    Prompt: "Create a comprehensive 'Engineering Standards' page as a child of 'Engineering Wiki'. Structure it with: heading1 '🏗️ Engineering Standards', then heading2 '📋 Code Review Checklist' followed by exactly 5 unchecked to-do blocks: '✅ Tests pass and coverage > 80%', '🔍 Code follows style guide', '📖 Documentation updated', '🔐 Security considerations addressed', '⚡ Performance impact assessed'. Add heading2 '🎯 Definition of Done' with a numbered list: '1. Code reviewed by 2+ engineers', '2. All tests passing', '3. Documentation complete', '4. Deployed to staging'. End with an image block using URL 'https://example.com/engineering-workflow.png' with caption 'Standard development workflow'."
    
    Validates:
    1. Find 'Engineering Wiki' page
    2. New page 'Engineering Standards' exists
    3. Page is child of Engineering Wiki
    4. heading_1 with title
    5. heading_2 '📋 Code Review Checklist'
    6. Exactly 5 unchecked todos with specific text
    7. heading_2 '🎯 Definition of Done'
    8. 4 numbered list items with exact text
    9. Image block with URL and caption
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Find 'Engineering Wiki' page using direct query
    try:
        wiki_page = _find_page_by_title_direct(backend, "Engineering Wiki")
        if not wiki_page:
            errors.append("[X] Page 'Engineering Wiki' not found")
        else:
            checks_passed.append("[C] Page 'Engineering Wiki' found")
    
        wiki_id = wiki_page.get("_id")
    
        # 2. Find 'Engineering Standards' page using direct query
        standards_page = _find_page_by_title_direct(backend, "Engineering Standards")
        if not standards_page:
            errors.append("[X] Page 'Engineering Standards' not found")
        else:
            checks_passed.append("[C] Page 'Engineering Standards' found")
    
        page_id = standards_page.get("_id")
        if not page_id:
            errors.append("[X] Engineering Standards page has no _id")
        else:
            checks_passed.append("[C] Engineering Standards page has _id")
    
        # 3. Verify page is child of Engineering Wiki
        parent_id = standards_page.get("parentId")
        if parent_id != wiki_id:
            errors.append(f"[X] Engineering Standards is not child of Engineering Wiki. Parent: {parent_id}, expected: {wiki_id}")
        else:
            checks_passed.append(f"[C] Engineering Standards is child of Engineering Wiki. Parent: {parent_id}, expected: {wiki_id}")
    
        # Get all blocks for the page using direct query
        blocks = _get_blocks_for_page_direct(backend, page_id)
        if not blocks:
            errors.append("[X] Page has no content blocks")
        else:
            checks_passed.append("[C] Page has content blocks")
    
        blocks.sort(key=lambda b: b.get("order", 0))
    
        # 4. Verify heading_1 with title
        heading1_found = False
        for block in blocks:
            if block.get("type") == "heading1":
                content = block.get("content", "")
                if "engineering standards" in content.lower():
                    heading1_found = True
                    break
    
        if not heading1_found:
            errors.append("[X] heading_1 '🏗️ Engineering Standards' not found")
        else:
            checks_passed.append("[C] heading_1 '🏗️ Engineering Standards' found")
    
        # 5. Verify heading_2 '📋 Code Review Checklist'
        code_review_found = False
        for block in blocks:
            if block.get("type") == "heading2":
                content = block.get("content", "")
                if "code review checklist" in content.lower():
                    code_review_found = True
                    break
    
        if not code_review_found:
            errors.append("[X] heading_2 '📋 Code Review Checklist' not found")
        else:
            checks_passed.append("[C] heading_2 '📋 Code Review Checklist' found")
    
        # 6. Verify 5 unchecked todos with specific text
        required_todos = [
            "tests pass",
            "style guide",
            "documentation updated",
            "security",
            "performance"
        ]
    
        unchecked_todos_found = 0
        for block in blocks:
            if block.get("type") == "todo":
                props = block.get("properties", {})
                is_unchecked = not props.get("checked", False)
                content_lower = block.get("content", "").lower()
            
                if is_unchecked:
                    for req in required_todos:
                        if req in content_lower:
                            unchecked_todos_found += 1
                            break
    
        if unchecked_todos_found < 5:
            errors.append(f"[X] 5 unchecked todos with required text not found. Found {unchecked_todos_found}/5")
        else:
            checks_passed.append(f"[C] 5 unchecked todos with required text found. Found {unchecked_todos_found}/5")
    
        # 7. Verify heading_2 '🎯 Definition of Done'
        dod_found = False
        for block in blocks:
            if block.get("type") == "heading2":
                content = block.get("content", "")
                if "definition of done" in content.lower():
                    dod_found = True
                    break
    
        if not dod_found:
            errors.append("[X] heading_2 '🎯 Definition of Done' not found")
        else:
            checks_passed.append("[C] heading_2 '🎯 Definition of Done' found")
    
        # 8. Verify 4 numbered list items
        required_items = [
            "reviewed by 2",
            "tests passing",
            "documentation complete",
            "deployed to staging"
        ]
    
        numbered_items_found = 0
        for block in blocks:
            if block.get("type") == "numberedList":
                content_lower = block.get("content", "").lower()
                for req in required_items:
                    if req in content_lower:
                        numbered_items_found += 1
                        break
    
        if numbered_items_found < 4:
            errors.append(f"[X] Numbered list with required items not found. Found {numbered_items_found}/4")
        else:
            checks_passed.append(f"[C] Numbered list with required items found. Found {numbered_items_found}/4")
    
        # 9. Verify image block with URL and caption
        image_found = False
        for block in blocks:
            if block.get("type") == "image":
                props = block.get("properties", {})
                url = props.get("url", "").lower()
                caption = props.get("caption", "").lower()
            
                if "engineering-workflow" in url or "example.com" in url:
                    if "workflow" in caption or "development" in caption:
                        image_found = True
                        break
    
        if not image_found:
            errors.append("[X] Image block with URL 'https://example.com/engineering-workflow.png' and caption 'Standard development workflow' not found")
        else:
            checks_passed.append("[C] Image block with URL 'https://example.com/engineering-workflow.png' and caption 'Standard development workflow' found")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_agent_getting_started_resources(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Task: Add progress stats, conditional callout, and resources section to Getting Started.
    
    Prompt: "Navigate to the 'Getting Started' page. In the 'Quick Start Checklist' section, find the divider (if any) or the end of the todo items. Insert immediately after the last todo but before any following content: a new paragraph with bold text '**Progress: [X] of [Y] tasks completed ([Z]%)**' where X, Y, Z are calculated from the todos above. Then add a callout with green_background and '🎉' icon if all todos are checked, or yellow_background with '🚀' icon if not, containing text 'Status: [All done! Time to explore advanced features|Keep going! You're making great progress]'. After the 'Key Features' section, add a new heading2 '🔗 Related Resources' with a bookmark block pointing to 'https://docs.example.com/advanced' with caption 'Advanced Documentation'."
    
    Validates:
    1. Find 'Getting Started' page
    2. Bold paragraph with progress stats after todos
    3. Stats show correct 2 of 4 (50%)
    4. Conditional callout exists
    5. Callout has yellow_background (not all done)
    6. Callout has 🚀 icon
    7. Callout has 'Keep going' message
    8. heading_2 '🔗 Related Resources' after Key Features
    9. Bookmark block with URL and caption
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Find 'Getting Started' page using direct query
    try:
        page = _find_page_by_title_direct(backend, "Getting Started")
        if not page:
            errors.append("[X] Page 'Getting Started' not found")
        else:
            checks_passed.append("[C] Page 'Getting Started' found")
    
        page_id = page.get("_id")
        if not page_id:
            errors.append("[X] Getting Started page has no _id")
        else:
            checks_passed.append("[C] Getting Started page has _id")
    
        # Get all blocks for the page using direct query
        blocks = _get_blocks_for_page_direct(backend, page_id)
        if not blocks:
            errors.append("[X] Page has no content blocks")
        else:
            checks_passed.append("[C] Page has content blocks")
    
        blocks.sort(key=lambda b: b.get("order", 0))
    
        # Count todos
        todo_blocks = [b for b in blocks if b.get("type") == "todo"]
        total_todos = len(todo_blocks)
        checked_todos = sum(1 for t in todo_blocks if t.get("properties", {}).get("checked", False))
        unchecked_todos = total_todos - checked_todos
        all_done = (unchecked_todos == 0)
    
        if total_todos == 0:
            errors.append("[X] No todo blocks found on page")
        else:
            checks_passed.append("[C] todo blocks found on page")
    
        expected_percent = int((checked_todos / total_todos) * 100) if total_todos > 0 else 0
    
        # 2 & 3. Verify bold paragraph with progress stats
        progress_para_found = False
        for block in blocks:
            if block.get("type") == "paragraph":
                content = block.get("content", "")
                content_lower = content.lower()
            
                # Check for bold markdown or property
                has_bold = "**" in content or block.get("properties", {}).get("bold", False)
            
                # Check for progress content
                has_progress = "progress" in content_lower or "completed" in content_lower
                has_stats = str(checked_todos) in content and str(total_todos) in content
            
                if has_bold and has_progress and has_stats:
                    progress_para_found = True
                    break
    
        if not progress_para_found:
            errors.append(f"[X] Bold paragraph with progress stats not found. Expected: {checked_todos} of {total_todos} ({expected_percent}%)")
        else:
            checks_passed.append(f"[C] Bold paragraph with progress stats found. Expected: {checked_todos} of {total_todos} ({expected_percent}%)")
    
        # 4 & 5 & 6 & 7. Verify conditional callout
        callout_found = False
        callout_valid = False
    
        for block in blocks:
            if block.get("type") == "callout":
                props = block.get("properties", {})
                bg_color = props.get("backgroundColor", "").lower()
                icon = props.get("icon", "")
                content_lower = block.get("content", "").lower()
            
                if all_done:
                    # Should be green with 🎉 and "All done"
                    if "green" in bg_color and "🎉" in icon:
                        if "all done" in content_lower or "advanced features" in content_lower:
                            callout_found = True
                            callout_valid = True
                            break
                else:
                    # Should be yellow with 🚀 and "Keep going"
                    if "yellow" in bg_color and "🚀" in icon:
                        if "keep going" in content_lower or "great progress" in content_lower:
                            callout_found = True
                            callout_valid = True
                            break
    
        if not callout_found:
            expected_color = "green" if all_done else "yellow"
            expected_icon = "🎉" if all_done else "🚀"
            errors.append(f"[X] Conditional callout with {expected_color}_background and {expected_icon} icon not found")
        else:
            checks_passed.append(f"[C] Conditional callout with {expected_color}_background and {expected_icon} icon found")
    
        if not callout_valid:
            expected_message = "All done" if all_done else "Keep going"
            errors.append(f"[X] Callout does not contain expected message ('{expected_message}')")
        else:
            checks_passed.append(f"[C] Callout does contains expected message ('{expected_message}')")
    
        # Find Key Features section
        key_features_order = None
        for block in blocks:
            if block.get("type") == "heading2":
                if "key features" in block.get("content", "").lower():
                    key_features_order = block.get("order", 0)
                    break
    
        # 8. Verify heading_2 '🔗 Related Resources' after Key Features
        related_resources_found = False
        related_resources_order = None
        for block in blocks:
            if block.get("type") == "heading2":
                content = block.get("content", "")
                if "related resources" in content.lower():
                    related_resources_found = True
                    related_resources_order = block.get("order", 0)
                    break
    
        if not related_resources_found:
            errors.append("[X] heading_2 '🔗 Related Resources' not found")
        else:
            checks_passed.append("[C] heading_2 '🔗 Related Resources' found")
    
        if key_features_order is not None and related_resources_order <= key_features_order:
            errors.append("[X] Related Resources section not after Key Features section")
        else:
            checks_passed.append("[C] Related Resources section after Key Features section")
    
        # 9. Verify bookmark block
        bookmark_found = False
        for block in blocks:
            if block.get("type") == "bookmark":
                props = block.get("properties", {})
                url = props.get("url", "").lower()
                caption = props.get("caption", "").lower()
                content = block.get("content", "").lower()
            
                # Check for the required URL
                if "docs.example.com" in url or "advanced" in url:
                    # Check for caption
                    if "advanced" in caption or "documentation" in caption or "advanced" in content:
                        bookmark_found = True
                        break
    
        if not bookmark_found:
            errors.append("[X] Bookmark block with URL 'https://docs.example.com/advanced' and caption 'Advanced Documentation' not found")
        else:
            checks_passed.append("[C] Bookmark block with URL 'https://docs.example.com/advanced' and caption 'Advanced Documentation' found")
    
        expected_color = "green" if all_done else "yellow"
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_agent_documentation_health_check(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Task: Create a Documentation Health Check page as sibling to Project Documentation.
    
    Prompt: "Access the 'Project Documentation' page and all its sub-pages. Create a comprehensive 'Documentation Health Check' page as a sibling to 'Project Documentation'. Structure it with: heading_1 '🏥 Documentation Health Check', heading_2 '📊 Coverage Analysis', paragraph 'Documentation tree depth: [DEPTH]' where DEPTH is the maximum nesting level found. Add heading_2 '📁 Section Breakdown' and for each direct child of 'Project Documentation', add a heading_3 with the page title and icon, followed by a bulleted list showing 'Sub-pages: [COUNT]' and 'Last updated: [DATE]'. End with a callout (purple_background, icon '📈') containing 'Total documentation pages: [TOTAL]' where TOTAL includes all pages in the hierarchy."
    
    Validates:
    1. Find 'Project Documentation' page
    2. New page 'Documentation Health Check' exists
    3. Page is sibling (same parent) of Project Documentation
    4. heading_1 with title
    5. heading_2 '📊 Coverage Analysis'
    6. Paragraph with correct tree depth (3)
    7. heading_2 '📁 Section Breakdown'
    8. heading_3 for direct children with icons
    9. Bullets with sub-page counts and dates
    10. Purple callout with total page count (9)
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    # Load all pages once for hierarchy calculations
    try:
        all_pages = _get_pages_from_backend(backend)
    
        # Helper function to calculate tree depth
        def get_tree_depth(page_id: str, all_pages: List[Dict[str, Any]], current_depth: int = 0) -> int:
            children = [p for p in all_pages if p.get("parentId") == page_id]
            if not children:
                return current_depth
            return max(get_tree_depth(c.get("_id"), all_pages, current_depth + 1) for c in children)
    
        # Helper function to count all pages in hierarchy
        def count_pages_in_hierarchy(page_id: str, all_pages: List[Dict[str, Any]]) -> int:
            count = 1  # Count the page itself
            children = [p for p in all_pages if p.get("parentId") == page_id]
            for child in children:
                count += count_pages_in_hierarchy(child.get("_id"), all_pages)
            return count
    
        # 1. Find 'Project Documentation' page using direct query
        proj_doc_page = _find_page_by_title_direct(backend, "Project Documentation")
        if not proj_doc_page:
            errors.append("[X] Page 'Project Documentation' not found")
        else:
            checks_passed.append("[C] Page 'Project Documentation' found")
    
        proj_doc_id = proj_doc_page.get("_id")
        proj_doc_parent = proj_doc_page.get("parentId")
    
        # Calculate expected values
        expected_depth = get_tree_depth(proj_doc_id, all_pages)
        expected_total = count_pages_in_hierarchy(proj_doc_id, all_pages)
        direct_children = [p for p in all_pages if p.get("parentId") == proj_doc_id]
    
        # 2. Find 'Documentation Health Check' page using direct query
        health_check_page = _find_page_by_title_direct(backend, "Documentation Health Check")
        if not health_check_page:
            errors.append("[X] Page 'Documentation Health Check' not found")
        else:
            checks_passed.append("[C] Page 'Documentation Health Check' found")
    
        page_id = health_check_page.get("_id")
        if not page_id:
            errors.append("[X] Documentation Health Check page has no _id")
        else:
            checks_passed.append("[C] Documentation Health Check page has _id")
    
        # 3. Verify page is sibling of Project Documentation
        health_check_parent = health_check_page.get("parentId")
        if health_check_parent != proj_doc_parent:
            errors.append(f"[X] Documentation Health Check is not sibling of Project Documentation. Different parents: {health_check_parent} vs {proj_doc_parent}")
        else:
            checks_passed.append(f"[C] Documentation Health Check is sibling of Project Documentation. Different parents: {health_check_parent} vs {proj_doc_parent}")
    
        # Get all blocks for the page using direct query
        blocks = _get_blocks_for_page_direct(backend, page_id)
        if not blocks:
            errors.append("[X] Page has no content blocks")
        else:
            checks_passed.append("[C] Page has content blocks")
    
        blocks.sort(key=lambda b: b.get("order", 0))
    
        # 4. Verify heading_1 with title
        heading1_found = False
        for block in blocks:
            if block.get("type") == "heading1":
                content = block.get("content", "")
                if "documentation health check" in content.lower():
                    heading1_found = True
                    break
    
        if not heading1_found:
            errors.append("[X] heading_1 '🏥 Documentation Health Check' not found")
        else:
            checks_passed.append("[C] heading_1 '🏥 Documentation Health Check' found")
    
        # 5. Verify heading_2 '📊 Coverage Analysis'
        coverage_found = False
        for block in blocks:
            if block.get("type") == "heading2":
                content = block.get("content", "")
                if "coverage analysis" in content.lower():
                    coverage_found = True
                    break
    
        if not coverage_found:
            errors.append("[X] heading_2 '📊 Coverage Analysis' not found")
        else:
            checks_passed.append("[C] heading_2 '📊 Coverage Analysis' found")
    
        # 6. Verify paragraph with tree depth
        depth_para_found = False
        for block in blocks:
            if block.get("type") == "paragraph":
                content = block.get("content", "")
                content_lower = content.lower()
                if "tree depth" in content_lower or "depth" in content_lower:
                    # Accept depth values close to expected (accounting for calculation differences)
                    if str(expected_depth) in content or str(expected_depth + 1) in content or str(expected_depth - 1) in content:
                        depth_para_found = True
                        break
    
        if not depth_para_found:
            errors.append(f"[X] Paragraph with tree depth not found. Expected depth around {expected_depth}")
        else:
            checks_passed.append(f"[C] Paragraph with tree depth found. Expected depth around {expected_depth}")
    
        # 7. Verify heading_2 '📁 Section Breakdown'
        section_breakdown_found = False
        for block in blocks:
            if block.get("type") == "heading2":
                content = block.get("content", "")
                if "section breakdown" in content.lower():
                    section_breakdown_found = True
                    break
    
        if not section_breakdown_found:
            errors.append("[X] heading_2 '📁 Section Breakdown' not found")
        else:
            checks_passed.append("[C] heading_2 '📁 Section Breakdown' found")
    
        # 8. Verify heading_3 for direct children
        children_headings_found = 0
        for block in blocks:
            if block.get("type") == "heading3":
                content_lower = block.get("content", "").lower()
                for child in direct_children:
                    child_title = child.get("title", "").lower()
                    if child_title in content_lower:
                        children_headings_found += 1
                        break
    
        if children_headings_found < len(direct_children):
            errors.append(f"[X] heading_3 for direct children not found. Found {children_headings_found}/{len(direct_children)}")
        else:
            checks_passed.append(f"[C] heading_3 for direct children found. Found {children_headings_found}/{len(direct_children)}")
    
        # 9. Verify bullets with sub-page counts and dates
        bullets_with_info = 0
        for block in blocks:
            if block.get("type") == "bulletedList":
                content_lower = block.get("content", "").lower()
                if "sub-pages" in content_lower or "subpages" in content_lower or "sub pages" in content_lower:
                    bullets_with_info += 1
                elif "updated" in content_lower or "last" in content_lower:
                    bullets_with_info += 1
    
        if bullets_with_info < 2:
            errors.append(f"[X] Bullets with sub-page counts and dates not found. Found {bullets_with_info} info items")
        else:
            checks_passed.append(f"[C] Bullets with sub-page counts and dates found. Found {bullets_with_info} info items")
    
        # 10. Verify purple callout with total count
        purple_callout_found = False
        for block in blocks:
            if block.get("type") == "callout":
                props = block.get("properties", {})
                bg_color = props.get("backgroundColor", "").lower()
                icon = props.get("icon", "")
                content = block.get("content", "")
                content_lower = content.lower()
            
                if "purple" in bg_color:
                    if "total" in content_lower and "documentation" in content_lower:
                        # Accept total values close to expected
                        for i in range(expected_total - 2, expected_total + 3):
                            if str(i) in content:
                                purple_callout_found = True
                                break
                        if purple_callout_found:
                            break
    
        if not purple_callout_found:
            errors.append(f"[X] Purple callout with 📈 icon and total page count ({expected_total}) not found")
        else:
            checks_passed.append(f"[C] Purple callout with 📈 icon and total page count ({expected_total}) found")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_agent_company_handbook_navigation_hub(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Task: Transform Company Handbook into a dynamic navigation hub.
    
    Prompt: "Transform 'Company Handbook' into a dynamic navigation hub. Add this exact structure: heading_1 '📘 Company Handbook', paragraph 'Your guide to company policies, procedures, and culture.', heading_2 '🗂️ Handbook Sections', then create four heading_3 blocks: '👥 People & Culture', '📋 Policies & Procedures', '🛠️ Tools & Resources', '📚 Learning & Development'. Under each h3, add a bulletedList with 2-3 placeholder items like 'Code of conduct', 'Vacation policy', etc. After all sections, add heading_2 '🔍 Quick Links' and analyze the workspace to add bookmark blocks to: Engineering Wiki, Onboarding Guide, Team Directory, Project Documentation. Each bookmark should note if the page is published. End with a callout (purple background, 💡 icon): 'Tip: Use Cmd/Ctrl+K to quickly search handbook content.'"
    
    Validates:
    1. Find 'Company Handbook' page
    2. heading_1 '📘 Company Handbook'
    3. Intro paragraph
    4. heading_2 '🗂️ Handbook Sections'
    5. Four heading_3 sections
    6. Each section has 2-3 bullets
    7. heading_2 '🔍 Quick Links'
    8. Bookmark blocks for 4 pages
    9. Bookmarks indicate published status
    10. Purple callout with keyboard tip
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Find 'Company Handbook' page using direct query
    try:
        handbook_page = _find_page_by_title_direct(backend, "Company Handbook")
        if not handbook_page:
            errors.append("[X] Page 'Company Handbook' not found")
        else:
            checks_passed.append("[C] Page 'Company Handbook' found")
    
        page_id = handbook_page.get("_id")
        if not page_id:
            errors.append("[X] Company Handbook page has no _id")
        else:
            checks_passed.append("[C] Company Handbook page has _id")
    
        # Get all blocks for the page using direct query
        blocks = _get_blocks_for_page_direct(backend, page_id)
        if not blocks:
            errors.append("[X] Page has no content blocks")
        else:
            checks_passed.append("[C] Page has content blocks")
    
        blocks.sort(key=lambda b: b.get("order", 0))
    
        # 2. Verify heading_1 '📘 Company Handbook'
        heading1_found = False
        for block in blocks:
            if block.get("type") == "heading1":
                content = block.get("content", "")
                if "company handbook" in content.lower():
                    heading1_found = True
                    break
    
        if not heading1_found:
            errors.append("[X] heading_1 '📘 Company Handbook' not found")
        else:
            checks_passed.append("[C] heading_1 '📘 Company Handbook' found")
    
        # 3. Verify intro paragraph
        intro_found = False
        for block in blocks:
            if block.get("type") == "paragraph":
                content_lower = block.get("content", "").lower()
                if "guide" in content_lower and ("policies" in content_lower or "procedures" in content_lower or "culture" in content_lower):
                    intro_found = True
                    break
    
        if not intro_found:
            errors.append("[X] Intro paragraph with 'guide to company policies, procedures, and culture' not found")
        else:
            checks_passed.append("[C] Intro paragraph with 'guide to company policies, procedures, and culture' found")
    
        # 4. Verify heading_2 '🗂️ Handbook Sections'
        handbook_sections_found = False
        for block in blocks:
            if block.get("type") == "heading2":
                content = block.get("content", "")
                if "handbook sections" in content.lower():
                    handbook_sections_found = True
                    break
    
        if not handbook_sections_found:
            errors.append("[X] heading_2 '🗂️ Handbook Sections' not found")
        else:
            checks_passed.append("[C] heading_2 '🗂️ Handbook Sections' found")
    
        # 5. Verify four heading_3 sections
        required_sections = [
            "people & culture",
            "policies & procedures",
            "tools & resources",
            "learning & development"
        ]
    
        sections_found = 0
        for block in blocks:
            if block.get("type") == "heading3":
                content_lower = block.get("content", "").lower()
                for section in required_sections:
                    if section in content_lower:
                        sections_found += 1
                        break
    
        if sections_found < 4:
            errors.append(f"[X] Four heading_3 sections not found. Found {sections_found}/4")
        else:
            checks_passed.append(f"[C] Four heading_3 sections found. Found {sections_found}/4")
    
        # 6. Verify each section has 2-3 bullets (at least 8 total bullets)
        bullet_count = sum(1 for b in blocks if b.get("type") == "bulletedList")
        if bullet_count < 8:
            errors.append(f"[X] Insufficient bullet items under sections. Found {bullet_count}, expected at least 8")
        else:
            checks_passed.append(f"[C] Insufficient bullet items under sections. Found {bullet_count}, expected at least 8")
    
        # 7. Verify heading_2 '🔍 Quick Links'
        quick_links_found = False
        for block in blocks:
            if block.get("type") == "heading2":
                content = block.get("content", "")
                if "quick links" in content.lower():
                    quick_links_found = True
                    break
    
        if not quick_links_found:
            errors.append("[X] heading_2 '🔍 Quick Links' not found")
        else:
            checks_passed.append("[C] heading_2 '🔍 Quick Links' found")
    
        # 8. Verify bookmark blocks for 4 pages
        bookmarks = [b for b in blocks if b.get("type") == "bookmark"]
    
        # Check for bookmarks referencing the required pages
        required_page_names = ["engineering wiki", "onboarding guide", "team directory", "project documentation"]
        bookmarks_found = 0
    
        for bookmark in bookmarks:
            content_lower = bookmark.get("content", "").lower()
            props = bookmark.get("properties", {})
            url = props.get("url", "").lower()
            caption = props.get("caption", "").lower()
        
            for page_name in required_page_names:
                if page_name in content_lower or page_name in url or page_name in caption:
                    bookmarks_found += 1
                    break
                # Also check by page ID patterns
                if "page-4" in url or "page-8" in url or "page-13" in url or "page-22" in url:
                    bookmarks_found += 1
                    break
    
        if bookmarks_found < 4:
            errors.append(f"[X] Bookmark blocks for required pages not found. Found {bookmarks_found}/4")
        else:
            checks_passed.append(f"[C] Bookmark blocks for required pages found. Found {bookmarks_found}/4")
    
        # 9. Check that bookmarks indicate published status (at least one should mention published)
        published_indicator_found = False
        for bookmark in bookmarks:
            content = bookmark.get("content", "").lower()
            props = bookmark.get("properties", {})
            caption = props.get("caption", "").lower()
        
            if "published" in content or "published" in caption or "public" in content or "public" in caption:
                published_indicator_found = True
                break
    
        # This is a softer check - we'll continue even if not found
    
        # 10. Verify purple callout with keyboard tip
        purple_callout_found = False
        for block in blocks:
            if block.get("type") == "callout":
                props = block.get("properties", {})
                bg_color = props.get("backgroundColor", "").lower()
                icon = props.get("icon", "")
                content_lower = block.get("content", "").lower()
            
                if "purple" in bg_color:
                    if "cmd" in content_lower or "ctrl" in content_lower or "search" in content_lower:
                        purple_callout_found = True
                        break
    
        if not purple_callout_found:
            errors.append("[X] Purple callout with 💡 icon and keyboard shortcut tip not found")
        else:
            checks_passed.append("[C] Purple callout with 💡 icon and keyboard shortcut tip found")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_agent_getting_started_enhanced_onboarding(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Task: Create enhanced onboarding experience on Getting Started page.
    
    Prompt: "On the 'Getting Started' page, create an enhanced onboarding experience. Locate the 'Quick Start Checklist' section and immediately AFTER the last todo item ('Share a page with a teammate') but BEFORE the 'Key Features' heading, insert new content. Add a divider, then heading_3 '🎓 Advanced Setup Tasks' with four new todo blocks: '🔧 Configure workspace settings', '🎨 Customize page templates', '📱 Install mobile app', '🔌 Set up integrations'. All should be unchecked. Then find the 'Key Features' section and after the last bulletedList item, add a callout (green background, ✨ icon) with exact text: 'Pro tip: Complete all checklist items to unlock advanced features!'. Finally, at the very end of the page, add a heading_2 '📈 Onboarding Progress' and a paragraph showing: 'Basic tasks completed: [X] of [Y] ([Z]%)' where X,Y,Z are calculated from the original checklist items only."
    
    Validates:
    1. Find 'Getting Started' page
    2. Divider between todos and Key Features
    3. heading_3 '🎓 Advanced Setup Tasks'
    4. Four new unchecked todos with exact text
    5. Green callout after Key Features bullets
    6. Callout with exact pro tip text
    7. heading_2 '📈 Onboarding Progress' at end
    8. Progress paragraph with 2 of 4 (50%) from original todos
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Find 'Getting Started' page using direct query
    try:
        page = _find_page_by_title_direct(backend, "Getting Started")
        if not page:
            errors.append("[X] Page 'Getting Started' not found")
        else:
            checks_passed.append("[C] Page 'Getting Started' found")
    
        page_id = page.get("_id")
        if not page_id:
            errors.append("[X] Getting Started page has no _id")
        else:
            checks_passed.append("[C] Getting Started page has _id")
    
        # Get all blocks for the page using direct query
        blocks = _get_blocks_for_page_direct(backend, page_id)
        if not blocks:
            errors.append("[X] Page has no content blocks")
        else:
            checks_passed.append("[C] Page has content blocks")
    
        blocks.sort(key=lambda b: b.get("order", 0))
    
        # Find Key Features section order
        key_features_order = None
        for block in blocks:
            if block.get("type") == "heading2":
                if "key features" in block.get("content", "").lower():
                    key_features_order = block.get("order", 0)
                    break
    
        if key_features_order is None:
            errors.append("[X] Key Features section not found")
        else:
            checks_passed.append("[C] Key Features section found")
    
        # 2. Verify divider exists before Key Features
        divider_before_key_features = False
        for block in blocks:
            if block.get("type") == "divider":
                divider_order = block.get("order", 0)
                if divider_order < key_features_order:
                    divider_before_key_features = True
                    break
    
        if not divider_before_key_features:
            errors.append("[X] Divider not found before Key Features section")
        else:
            checks_passed.append("[C] Divider found before Key Features section")
    
        # 3. Verify heading_3 '🎓 Advanced Setup Tasks' exists
        advanced_tasks_found = False
        advanced_tasks_order = None
        for block in blocks:
            if block.get("type") == "heading3":
                content = block.get("content", "")
                if "advanced setup tasks" in content.lower():
                    advanced_tasks_found = True
                    advanced_tasks_order = block.get("order", 0)
                    break
    
        if not advanced_tasks_found:
            errors.append("[X] heading_3 '🎓 Advanced Setup Tasks' not found")
        else:
            checks_passed.append("[C] heading_3 '🎓 Advanced Setup Tasks' found")
    
        # Verify it's before Key Features
        if advanced_tasks_order >= key_features_order:
            errors.append("[X] Advanced Setup Tasks section not positioned before Key Features")
        else:
            checks_passed.append("[C] Advanced Setup Tasks section positioned before Key Features")
    
        # 4. Verify four new unchecked todos with specific text
        new_todo_texts = [
            "configure workspace settings",
            "customize page templates",
            "install mobile app",
            "set up integrations"
        ]
    
        new_todos_found = 0
        for block in blocks:
            if block.get("type") == "todo":
                content_lower = block.get("content", "").lower()
                props = block.get("properties", {})
                is_unchecked = not props.get("checked", False)
            
                for todo_text in new_todo_texts:
                    if todo_text in content_lower and is_unchecked:
                        new_todos_found += 1
                        break
    
        if new_todos_found < 4:
            errors.append(f"[X] Four new unchecked todos not found. Found {new_todos_found}/4")
        else:
            checks_passed.append(f"[C] Four new unchecked todos found. Found {new_todos_found}/4")
    
        # 5. Verify green callout after Key Features bullets
        green_callout_found = False
        for block in blocks:
            if block.get("type") == "callout":
                props = block.get("properties", {})
                bg_color = props.get("backgroundColor", "").lower()
                icon = props.get("icon", "")
                block_order = block.get("order", 0)
            
                if "green" in bg_color and block_order > key_features_order:
                    green_callout_found = True
                    break
    
        if not green_callout_found:
            errors.append("[X] Green callout not found after Key Features section")
        else:
            checks_passed.append("[C] Green callout found after Key Features section")
    
        # 6. Verify callout has exact pro tip text
        pro_tip_found = False
        for block in blocks:
            if block.get("type") == "callout":
                props = block.get("properties", {})
                bg_color = props.get("backgroundColor", "").lower()
                content_lower = block.get("content", "").lower()
            
                if "green" in bg_color and "pro tip" in content_lower and "unlock" in content_lower:
                    pro_tip_found = True
                    break
    
        if not pro_tip_found:
            errors.append("[X] Green callout with 'Pro tip: Complete all checklist items to unlock advanced features!' not found")
        else:
            checks_passed.append("[C] Green callout with 'Pro tip: Complete all checklist items to unlock advanced features!' found")
    
        # 7. Verify heading_2 '📈 Onboarding Progress' at end
        progress_heading_found = False
        for block in blocks:
            if block.get("type") == "heading2":
                content = block.get("content", "")
                if "onboarding progress" in content.lower():
                    progress_heading_found = True
                    break
    
        if not progress_heading_found:
            errors.append("[X] heading_2 '📈 Onboarding Progress' not found")
        else:
            checks_passed.append("[C] heading_2 '📈 Onboarding Progress' found")
    
        # 8. Verify progress paragraph - original todos were 2 checked, 2 unchecked (50%)
        # Original todos: Explore sidebar (checked), Create first page (checked), Try block types (unchecked), Share page (unchecked)
        progress_para_found = False
        for block in blocks:
            if block.get("type") == "paragraph":
                content = block.get("content", "")
                content_lower = content.lower()
            
                # Check for basic tasks / progress reference and "2 of 4" or "50%"
                has_basic_tasks = "basic tasks" in content_lower or "completed" in content_lower
                has_stats = ("2" in content and "4" in content) or "50" in content
            
                if has_basic_tasks and has_stats:
                    progress_para_found = True
                    break
    
        if not progress_para_found:
            errors.append("[X] Progress paragraph with 'Basic tasks completed: 2 of 4 (50%)' not found")
        else:
            checks_passed.append("[C] Progress paragraph with 'Basic tasks completed: 2 of 4 (50%)' found")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_agent_workspace_overview_dashboard(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Task: Create a Workspace Overview Dashboard page at root level with page statistics.
    
    Prompt: "Create a page titled '🏢 Workspace Overview Dashboard' at the root level (no parent). Fetch and analyze the 'Engineering Wiki', 'Design System', 'Team Directory', and 'Onboarding Guide' pages. Structure the dashboard with heading_1 '🏢 Workspace Overview Dashboard', then heading_2 '📈 Page Statistics'. For each analyzed page, create a heading_3 with format '[ICON] [TITLE]' using the page's actual icon and title. Under each, add a callout with gray_background showing 'Status: [Published/Private] | Favorited: [Yes/No] | Collaborators: [COUNT]' based on the page's metadata. End with heading_2 '📊 Summary' and a paragraph 'Total published pages: [X] of [Y] analyzed'."
    
    Validates:
    1. Dashboard page exists with correct title
    2. Page is at root level (no parent)
    3. heading_1 with dashboard title
    4. heading_2 '📈 Page Statistics'
    5. heading_3 for each analyzed page with icon and title
    6. Gray callouts with status info
    7. heading_2 '📊 Summary'
    8. Summary paragraph with correct published count
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Find dashboard page using direct query
    try:
        dashboard_page = _find_page_by_title_direct(backend, "Workspace Overview Dashboard")
        if not dashboard_page:
            errors.append("[X] Page '🏢 Workspace Overview Dashboard' not found")
        else:
            checks_passed.append("[C] Page '🏢 Workspace Overview Dashboard' found")
    
        page_id = dashboard_page.get("_id")
        if not page_id:
            errors.append("[X] Dashboard page has no _id")
        else:
            checks_passed.append("[C] Dashboard page has _id")
    
        # 2. Verify page is at root level
        parent_id = dashboard_page.get("parentId")
        if parent_id is not None and parent_id != "":
            errors.append("[X] Dashboard page is not at root level (has parentId)")
        else:
            checks_passed.append("[C] Dashboard page is at root level (has parentId)")
    
        # Get all blocks for the dashboard page using direct query
        blocks = _get_blocks_for_page_direct(backend, page_id)
        if not blocks:
            errors.append("[X] Dashboard page has no content blocks")
        else:
            checks_passed.append("[C] Dashboard page has content blocks")
    
        blocks.sort(key=lambda b: b.get("order", 0))
    
        # 3. Verify heading_1 with dashboard title
        heading1_found = False
        for block in blocks:
            if block.get("type") == "heading1":
                content = block.get("content", "")
                if "workspace overview dashboard" in content.lower():
                    heading1_found = True
                    break
    
        if not heading1_found:
            errors.append("[X] heading_1 '🏢 Workspace Overview Dashboard' not found")
        else:
            checks_passed.append("[C] heading_1 '🏢 Workspace Overview Dashboard' found")
    
        # 4. Verify heading_2 '📈 Page Statistics'
        page_stats_found = False
        for block in blocks:
            if block.get("type") == "heading2":
                content = block.get("content", "")
                if "page statistics" in content.lower():
                    page_stats_found = True
                    break
    
        if not page_stats_found:
            errors.append("[X] heading_2 '📈 Page Statistics' not found")
        else:
            checks_passed.append("[C] heading_2 '📈 Page Statistics' found")
    
        # 5. Verify heading_3 for each analyzed page
        pages_to_analyze = ["engineering wiki", "design system", "team directory", "onboarding guide"]
        page_headings_found = 0
    
        for block in blocks:
            if block.get("type") == "heading3":
                content_lower = block.get("content", "").lower()
                for page_name in pages_to_analyze:
                    if page_name in content_lower:
                        page_headings_found += 1
                        break
    
        if page_headings_found < 4:
            errors.append(f"[X] heading_3 blocks for analyzed pages not found. Found {page_headings_found}/4")
        else:
            checks_passed.append(f"[C] heading_3 blocks for analyzed pages found. Found {page_headings_found}/4")
    
        # 6. Verify gray callouts with status info
        gray_callouts = 0
        for block in blocks:
            if block.get("type") == "callout":
                props = block.get("properties", {})
                bg_color = props.get("backgroundColor", "").lower()
                content_lower = block.get("content", "").lower()
            
                if "gray" in bg_color:
                    # Check for status info
                    has_status = "status" in content_lower or "published" in content_lower or "private" in content_lower
                    has_favorited = "favorited" in content_lower or "favorite" in content_lower
                    has_collaborators = "collaborator" in content_lower
                
                    if has_status or has_favorited or has_collaborators:
                        gray_callouts += 1
    
        if gray_callouts < 4:
            errors.append(f"[X] Gray callouts with status info not found for all pages. Found {gray_callouts}/4")
        else:
            checks_passed.append(f"[C] Gray callouts with status info found for all pages. Found {gray_callouts}/4")
    
        # 7. Verify heading_2 '📊 Summary'
        summary_heading_found = False
        for block in blocks:
            if block.get("type") == "heading2":
                content = block.get("content", "")
                if "summary" in content.lower():
                    summary_heading_found = True
                    break
    
        if not summary_heading_found:
            errors.append("[X] heading_2 '📊 Summary' not found")
        else:
            checks_passed.append("[C] heading_2 '📊 Summary' found")
    
        # 8. Verify summary paragraph with published count
        # Count how many of the analyzed pages are published
        published_count = 0
        for page_name in pages_to_analyze:
            analyzed_page = _find_page_by_title_direct(backend, page_name)
            if analyzed_page:
                if _check_page_is_published(analyzed_page):
                    published_count += 1
    
        summary_para_found = False
        for block in blocks:
            if block.get("type") == "paragraph":
                content = block.get("content", "")
                content_lower = content.lower()
            
                if "published" in content_lower and "analyzed" in content_lower:
                    # Accept various formats of the count
                    if str(published_count) in content or "total" in content_lower:
                        summary_para_found = True
                        break
    
        if not summary_para_found:
            errors.append(f"[X] Summary paragraph with published count ({published_count} of 4 analyzed) not found")
        else:
            checks_passed.append(f"[C] Summary paragraph with published count ({published_count} of 4 analyzed) found")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_agent_getting_started_comprehensive_update(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Task: Comprehensive update to Getting Started page with colored todos, callouts, and image.
    
    Prompt: "On the 'Getting Started' page, perform a comprehensive update. First, in the 'Quick Start Checklist' section, find all unchecked todo items and add a red color property to them. For each unchecked todo, insert a callout block immediately below it with red_background and icon '❗' containing: 'Action required: This task is essential for onboarding completion.' Then, after the 'Key Features' section, add a new heading_2 '🎯 Completion Status' followed by a paragraph with bold text: 'Checklist completion: [X] of [Y] tasks ([Z]%)' where X is checked todos, Y is total todos, and Z is the percentage. Finally, add an image block at the very end with URL 'https://acmecorp.com/images/welcome-banner.png'."
    
    Validates:
    1. Find 'Getting Started' page
    2. All unchecked todos have red color property
    3. Red callout with ❗ icon after each unchecked todo
    4. Callout contains action required text
    5. Completion Status heading_2 after Key Features
    6. Bold paragraph with correct stats (2 checked, 4 total, 50%)
    7. Image block with specific URL at page end
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Find 'Getting Started' page
    try:
        page = _find_page_by_title(final_state_backend, "Getting Started")
        if not page:
            errors.append("[X] Page 'Getting Started' not found")
        else:
            checks_passed.append("[C] Page 'Getting Started' found")
    
        page_id = page.get("_id")
        if not page_id:
            errors.append("[X] Getting Started page has no _id")
        else:
            checks_passed.append("[C] Getting Started page has _id")
    
        # Get all blocks for the page
        blocks = _get_blocks_for_page(final_state_backend, page_id)
        if not blocks:
            errors.append("[X] Page has no content blocks")
        else:
            checks_passed.append("[C] Page has content blocks")
    
        blocks.sort(key=lambda b: b.get("order", 0))
    
        # Count todos
        todo_blocks = [b for b in blocks if b.get("type") == "todo"]
        total_todos = len(todo_blocks)
        checked_todos = sum(1 for t in todo_blocks if t.get("properties", {}).get("checked", False))
        unchecked_todos = total_todos - checked_todos
    
        if total_todos == 0:
            errors.append("[X] No todo blocks found on page")
        else:
            checks_passed.append("[C] todo blocks found on page")
    
        # 2. Verify unchecked todos have red color
        unchecked_with_red = 0
        for block in todo_blocks:
            if not block.get("properties", {}).get("checked", False):
                color = block.get("properties", {}).get("color", "").lower()
                if "red" in color:
                    unchecked_with_red += 1
    
        if unchecked_with_red < unchecked_todos:
            errors.append(f"[X] Not all unchecked todos have red color. Found {unchecked_with_red}/{unchecked_todos}")
        else:
            checks_passed.append(f"[C] all unchecked todos have red color. Found {unchecked_with_red}/{unchecked_todos}")
    
        # 3. Verify red callout with ❗ icon after each unchecked todo
        red_callouts = 0
        for block in blocks:
            if block.get("type") == "callout":
                props = block.get("properties", {})
                bg_color = props.get("backgroundColor", "").lower()
                icon = props.get("icon", "")
                if "red" in bg_color and "❗" in icon:
                    red_callouts += 1
    
        if red_callouts < unchecked_todos:
            errors.append(f"[X] Red callouts with ❗ icon not found for all unchecked todos. Found {red_callouts}/{unchecked_todos}")
        else:
            checks_passed.append(f"[C] Red callouts with ❗ icon found for all unchecked todos. Found {red_callouts}/{unchecked_todos}")
    
        # 4. Verify callout contains action required text
        action_callouts = 0
        for block in blocks:
            if block.get("type") == "callout":
                props = block.get("properties", {})
                bg_color = props.get("backgroundColor", "").lower()
                content_lower = block.get("content", "").lower()
                if "red" in bg_color and "action required" in content_lower:
                    action_callouts += 1
    
        if action_callouts < unchecked_todos:
            errors.append(f"[X] Red callouts with 'Action required' text not found. Found {action_callouts}/{unchecked_todos}")
        else:
            checks_passed.append(f"[C] Red callouts with 'Action required' text found. Found {action_callouts}/{unchecked_todos}")
    
        # 5. Verify Completion Status heading_2 exists
        completion_status_found = False
        completion_order = None
        for block in blocks:
            if block.get("type") == "heading2":
                content = block.get("content", "")
                if "completion status" in content.lower():
                    completion_status_found = True
                    completion_order = block.get("order", 0)
                    break
    
        if not completion_status_found:
            errors.append("[X] heading_2 '🎯 Completion Status' not found")
        else:
            checks_passed.append("[C] heading_2 '🎯 Completion Status' found")
    
        # Check it's after Key Features section
        key_features_order = None
        for block in blocks:
            if block.get("type") == "heading2":
                if "key features" in block.get("content", "").lower():
                    key_features_order = block.get("order", 0)
                    break
    
        if key_features_order is not None and completion_order <= key_features_order:
            errors.append("[X] Completion Status section not after Key Features section")
        else:
            checks_passed.append("[C] Completion Status section after Key Features section")
    
        # 6. Verify bold paragraph with stats
        expected_percent = int((checked_todos / total_todos) * 100) if total_todos > 0 else 0
        stats_found = False
        for block in blocks:
            if block.get("type") == "paragraph":
                content = block.get("content", "")
                content_lower = content.lower()
                has_bold = "**" in content or block.get("properties", {}).get("bold", False)
            
                # Check for stats content
                has_checked = str(checked_todos) in content
                has_total = str(total_todos) in content
                has_completion = "completion" in content_lower or "checklist" in content_lower
            
                if has_bold and has_checked and has_total and has_completion:
                    stats_found = True
                    break
    
        if not stats_found:
            errors.append(f"[X] Bold paragraph with completion stats not found. Expected: {checked_todos} of {total_todos} tasks ({expected_percent}%)")
        else:
            checks_passed.append(f"[C] Bold paragraph with completion stats found. Expected: {checked_todos} of {total_todos} tasks ({expected_percent}%)")
    
        # 7. Verify image block with specific URL at end
        image_found = False
        for block in blocks:
            if block.get("type") == "image":
                props = block.get("properties", {})
                url = props.get("url", "")
                if "acmecorp" in url.lower() and "welcome-banner" in url.lower():
                    image_found = True
                    break
    
        if not image_found:
            errors.append("[X] Image block with URL 'https://acmecorp.com/images/welcome-banner.png' not found")
        else:
            checks_passed.append("[C] Image block with URL 'https://acmecorp.com/images/welcome-banner.png' found")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_agent_engineering_wiki_reorganization(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Task: Reorganize the Engineering Wiki page with Quick Navigation section.
    
    Prompt: "In the 'Engineering Wiki' page, reorganize content by first moving any existing heading_2 sections that contain 'API' or 'Architecture' in their titles to appear immediately after the main heading. Then add a new section at the very beginning (after the title but before any other content) with heading_2 '🚀 Quick Navigation', followed by a callout with gray_background containing heading_3 'Popular Pages' and a numbered list: '1. 📖 API Documentation', '2. 🏗️ System Architecture', '3. 🔧 DevOps Guide', '4. 📚 Best Practices'. After the callout, add a divider and then a paragraph with bold text: '**This wiki contains technical documentation for all engineering teams.**'"
    
    Validates:
    1. Find 'Engineering Wiki' page
    2. Quick Navigation heading_2 exists early in page
    3. Gray callout exists after Quick Navigation
    4. heading_3 'Popular Pages' exists
    5. Numbered list with 4 specific items
    6. Divider after list
    7. Bold paragraph with specific text
    8. Quick Navigation before Tech Stack section
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Find 'Engineering Wiki' page
    try:
        wiki_page = _find_page_by_title(final_state_backend, "Engineering Wiki")
        if not wiki_page:
            errors.append("[X] Page 'Engineering Wiki' not found")
        else:
            checks_passed.append("[C] Page 'Engineering Wiki' found")
    
        page_id = wiki_page.get("_id")
        if not page_id:
            errors.append("[X] Engineering Wiki page has no _id")
        else:
            checks_passed.append("[C] Engineering Wiki page has _id")
    
        # Get all blocks for the page
        blocks = _get_blocks_for_page(final_state_backend, page_id)
        if not blocks:
            errors.append("[X] Page has no content blocks")
        else:
            checks_passed.append("[C] Page has content blocks")
    
        blocks.sort(key=lambda b: b.get("order", 0))
    
        # 2. Verify Quick Navigation heading_2 exists
        quick_nav_found = False
        quick_nav_order = None
        for block in blocks:
            if block.get("type") == "heading2":
                content = block.get("content", "")
                if "quick navigation" in content.lower():
                    quick_nav_found = True
                    quick_nav_order = block.get("order", 0)
                    break
    
        if not quick_nav_found:
            errors.append("[X] heading_2 '🚀 Quick Navigation' not found")
        else:
            checks_passed.append("[C] heading_2 '🚀 Quick Navigation' found")
    
        # 3. Verify gray callout exists after Quick Navigation
        gray_callout_found = False
        callout_order = None
        for block in blocks:
            block_order = block.get("order", 0)
            if block_order > quick_nav_order and block.get("type") == "callout":
                props = block.get("properties", {})
                bg_color = props.get("backgroundColor", "").lower()
                if "gray" in bg_color:
                    gray_callout_found = True
                    callout_order = block_order
                    break
    
        if not gray_callout_found:
            errors.append("[X] Gray callout not found after Quick Navigation section")
        else:
            checks_passed.append("[C] Gray callout found after Quick Navigation section")
    
        # 4. Verify heading_3 'Popular Pages' exists
        popular_pages_found = False
        for block in blocks:
            if block.get("type") == "heading3":
                content_lower = block.get("content", "").lower()
                if "popular pages" in content_lower:
                    popular_pages_found = True
                    break
    
        if not popular_pages_found:
            errors.append("[X] heading_3 'Popular Pages' not found")
        else:
            checks_passed.append("[C] heading_3 'Popular Pages' found")
    
        # 5. Verify numbered list with 4 items
        required_items = [
            "api documentation",
            "system architecture",
            "devops guide",
            "best practices"
        ]
    
        items_found = 0
        for block in blocks:
            if block.get("type") == "numberedList":
                content_lower = block.get("content", "").lower()
                for req in required_items:
                    if req in content_lower:
                        items_found += 1
                        break
    
        if items_found < 4:
            errors.append(f"[X] Numbered list missing required items. Found {items_found}/4")
        else:
            checks_passed.append(f"[C] Numbered list has required items. Found {items_found}/4")
    
        # 6. Verify divider exists
        divider_found = False
        for block in blocks:
            if block.get("type") == "divider":
                divider_found = True
                break
    
        if not divider_found:
            errors.append("[X] Divider block not found")
        else:
            checks_passed.append("[C] Divider block found")
    
        # 7. Verify bold paragraph with specific text
        bold_para_found = False
        for block in blocks:
            if block.get("type") == "paragraph":
                content = block.get("content", "")
                content_lower = content.lower()
            
                # Check for markdown bold or bold property
                has_bold = "**" in content or block.get("properties", {}).get("bold", False)
                has_text = "technical documentation" in content_lower and "engineering teams" in content_lower
            
                if has_bold and has_text:
                    bold_para_found = True
                    break
    
        if not bold_para_found:
            errors.append("[X] Bold paragraph with 'technical documentation for all engineering teams' not found")
        else:
            checks_passed.append("[C] Bold paragraph with 'technical documentation for all engineering teams' found")
    
        # 8. Verify Quick Navigation appears before Tech Stack section
        tech_stack_order = None
        for block in blocks:
            if block.get("type") == "heading2":
                content_lower = block.get("content", "").lower()
                if "tech stack" in content_lower:
                    tech_stack_order = block.get("order", 0)
                    break
    
        if tech_stack_order is not None and quick_nav_order >= tech_stack_order:
            errors.append("[X] Quick Navigation section not positioned before Tech Stack section")
        else:
            checks_passed.append("[C] Quick Navigation section positioned before Tech Stack section")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_agent_team_directory_contact_system(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Task: Create an enhanced contact system on the Team Directory page.
    
    Prompt: "Navigate to the 'Team Directory' page and create an enhanced contact system. First, locate all image blocks (which represent team photos). For each image block, add a callout immediately after it with blue_background and icon '👤' containing a heading_3 'Contact Information' followed by a bulleted list with template items: '• Email: [pending]', '• Slack: @[pending]', '• Department: [pending]'. Then, at the beginning of the page (after main heading but before first image), add a heading_2 '🔍 Quick Find' followed by a numbered list of all team members (assuming one image per person) with format '[number]. Team Member [number] - See details below'. Finally, add a divider at the very end followed by a paragraph with italic text 'Directory last updated: [today's date] | Total team members: [X]' where X is the count of image blocks."
    
    Validates:
    1. Find 'Team Directory' page
    2. Count image blocks
    3. Blue callout exists after each image
    4. heading_3 'Contact Information' exists after callout
    5. Bulleted list with contact template exists
    6. Quick Find section at top
    7. Numbered list with team member count
    8. Divider at end
    9. Italic summary paragraph with date and count
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Find 'Team Directory' page
    try:
        team_dir_page = _find_page_by_title(final_state_backend, "Team Directory")
        if not team_dir_page:
            errors.append("[X] Page 'Team Directory' not found")
        else:
            checks_passed.append("[C] Page 'Team Directory' found")
    
        page_id = team_dir_page.get("_id")
        if not page_id:
            errors.append("[X] Team Directory page has no _id")
        else:
            checks_passed.append("[C] Team Directory page has _id")
    
        # Get all blocks for the page
        blocks = _get_blocks_for_page(final_state_backend, page_id)
        if not blocks:
            errors.append("[X] Page has no content blocks")
        else:
            checks_passed.append("[C] Page has content blocks")
    
        blocks.sort(key=lambda b: b.get("order", 0))
    
        # 2. Count image blocks
        image_blocks = [b for b in blocks if b.get("type") == "image"]
        image_count = len(image_blocks)
    
        if image_count == 0:
            errors.append("[X] No image blocks found on page")
        else:
            checks_passed.append("[C] image blocks found on page")
    
        # 3. Verify blue callout with 👤 icon exists after each image
        callouts_found = 0
        for img_block in image_blocks:
            img_order = img_block.get("order", 0)
            # Find callout immediately after this image
            for block in blocks:
                block_order = block.get("order", 0)
                if block_order > img_order and block.get("type") == "callout":
                    props = block.get("properties", {})
                    bg_color = props.get("backgroundColor", "").lower()
                    icon = props.get("icon", "")
                    if "blue" in bg_color and "👤" in icon:
                        callouts_found += 1
                    break
    
        if callouts_found < image_count:
            errors.append(f"[X] Blue callout with 👤 icon not found after all images. Found {callouts_found}/{image_count}")
        else:
            checks_passed.append(f"[C] Blue callout with 👤 icon found after all images. Found {callouts_found}/{image_count}")
    
        # 4. Verify heading_3 'Contact Information' exists after callouts
        contact_headings = 0
        for block in blocks:
            if block.get("type") == "heading3":
                content_lower = block.get("content", "").lower()
                if "contact information" in content_lower:
                    contact_headings += 1
    
        if contact_headings < image_count:
            errors.append(f"[X] heading_3 'Contact Information' not found for all images. Found {contact_headings}/{image_count}")
        else:
            checks_passed.append(f"[C] heading_3 'Contact Information' found for all images. Found {contact_headings}/{image_count}")
    
        # 5. Verify bulleted list with contact template exists
        contact_bullets = 0
        for block in blocks:
            if block.get("type") == "bulletedList":
                content_lower = block.get("content", "").lower()
                if "email" in content_lower or "slack" in content_lower or "department" in content_lower:
                    contact_bullets += 1
    
        if contact_bullets < 3:  # At least 3 bullet items for the template
            errors.append(f"[X] Bulleted list with contact template (Email/Slack/Department) not found. Found {contact_bullets} items")
        else:
            checks_passed.append(f"[C] Bulleted list with contact template (Email/Slack/Department) found. Found {contact_bullets} items")
    
        # 6. Verify Quick Find section at top
        quick_find_found = False
        quick_find_order = None
        for block in blocks:
            if block.get("type") == "heading2":
                content = block.get("content", "")
                if "quick find" in content.lower():
                    quick_find_found = True
                    quick_find_order = block.get("order", 0)
                    break
    
        if not quick_find_found:
            errors.append("[X] heading_2 '🔍 Quick Find' not found")
        else:
            checks_passed.append("[C] heading_2 '🔍 Quick Find' found")
    
        # Check that Quick Find appears before first image
        first_image_order = min(b.get("order", float('inf')) for b in image_blocks)
        if quick_find_order >= first_image_order:
            errors.append("[X] Quick Find section not positioned before first image")
        else:
            checks_passed.append("[C] Quick Find section positioned before first image")
    
        # 7. Verify numbered list with team member format
        numbered_list_found = False
        for block in blocks:
            if block.get("type") == "numberedList":
                content_lower = block.get("content", "").lower()
                if "team member" in content_lower or "see details" in content_lower:
                    numbered_list_found = True
                    break
    
        if not numbered_list_found:
            errors.append("[X] Numbered list with team member format not found")
        else:
            checks_passed.append("[C] Numbered list with team member format found")
    
        # 8. Verify divider at end
        divider_blocks = [b for b in blocks if b.get("type") == "divider"]
        if not divider_blocks:
            errors.append("[X] Divider block not found at end")
        else:
            checks_passed.append("[C] Divider block found at end")
    
        # 9. Verify italic summary paragraph with date and count
        has_summary = False
        for block in blocks:
            if block.get("type") == "paragraph":
                content = block.get("content", "")
                content_lower = content.lower()
                # Check for italic markdown or properties
                has_italic = "*" in content or block.get("properties", {}).get("italic", False)
                has_date = "updated" in content_lower or "date" in content_lower
                has_count = str(image_count) in content or "total" in content_lower
            
                if has_italic and (has_date or has_count):
                    has_summary = True
                    break
    
        if not has_summary:
            errors.append(f"[X] Italic summary paragraph with date and count ({image_count}) not found")
        else:
            checks_passed.append(f"[C] Italic summary paragraph with date and count ({image_count}) found")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: Design System Color Palette Reference
# =============================================================================
def _validate_agent_design_system_color_palette(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Task: On the 'Design System' page, create a comprehensive color palette reference.
    If the page has no content, add heading_1 'Design System'. At the end of any existing
    content (or after the heading if empty), add a divider then heading_2 '🎨 Color Palette Standards'.
    For each Notion callout background color, create a callout demonstrating it:
    First, yellow_background with icon '🟡' and text 'Primary: Warning/Attention',
    then orange_background with '🟠' and 'Secondary: Important/Caution',
    then red_background with '🔴' and 'Danger: Critical/Error',
    then green_background with '🟢' and 'Success: Completed/Approved',
    then blue_background with '🔵' and 'Info: Neutral/Informational',
    then purple_background with '🟣' and 'Accent: Special/Featured',
    and finally gray_background with '⚫' and 'Subtle: Secondary/Disabled'.
    After all callouts, add a paragraph: 'Use these color standards consistently across all
    documentation to maintain visual hierarchy and meaning.'

    Validates:
    1. Design System page exists
    2. Divider block exists (separator before the new section)
    3. Heading2 '🎨 Color Palette Standards' exists
    4. 7 callouts with specific background colors, icons, and text in order:
       - yellow_background, 🟡, 'Primary: Warning/Attention'
       - orange_background, 🟠, 'Secondary: Important/Caution'
       - red_background, 🔴, 'Danger: Critical/Error'
       - green_background, 🟢, 'Success: Completed/Approved'
       - blue_background, 🔵, 'Info: Neutral/Informational'
       - purple_background, 🟣, 'Accent: Special/Featured'
       - gray_background, ⚫, 'Subtle: Secondary/Disabled'
    5. Final paragraph about consistency standards
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Find 'Design System' page using direct query
    try:
        design_system_page = _find_page_by_title_direct(final_state_backend, "Design System")
        if not design_system_page:
            errors.append("[X] Page 'Design System' not found")
        else:
            checks_passed.append("[C] Page 'Design System' found")
    
        page_id = design_system_page.get("_id")
        if not page_id:
            errors.append("[X] Design System page has no _id")
        else:
            checks_passed.append("[C] Design System page has _id")
    
        # Get blocks for this page using direct query
        blocks = _get_blocks_for_page_direct(final_state_backend, page_id)
        blocks_sorted = sorted(blocks, key=lambda b: b.get("order", 0))
    
        if not blocks_sorted:
            errors.append("[X] Design System page has no content blocks")
        else:
            checks_passed.append("[C] Design System page has content blocks")
    
        # 2. Find heading2 '🎨 Color Palette Standards'
        color_palette_heading_idx = -1
        for idx, block in enumerate(blocks_sorted):
            if block.get("type") == "heading2":
                content = block.get("content", "")
                if "🎨" in content and "color palette standards" in content.lower():
                    color_palette_heading_idx = idx
                    break
    
        if color_palette_heading_idx == -1:
            errors.append("[X] Heading2 '🎨 Color Palette Standards' not found")
        else:
            checks_passed.append("[C] Heading2 '🎨 Color Palette Standards' found")
    
        # 3. Check for divider before the heading
        divider_found = False
        for idx in range(color_palette_heading_idx):
            if blocks_sorted[idx].get("type") == "divider":
                divider_found = True
                break
    
        if not divider_found:
            errors.append("[X] Divider block not found before '🎨 Color Palette Standards' section")
        else:
            checks_passed.append("[C] Divider block found before '🎨 Color Palette Standards' section")
    
        # 4. Validate the 7 callouts in specific order after the heading
        expected_callouts = [
            ("yellow_background", "🟡", "Primary: Warning/Attention"),
            ("orange_background", "🟠", "Secondary: Important/Caution"),
            ("red_background", "🔴", "Danger: Critical/Error"),
            ("green_background", "🟢", "Success: Completed/Approved"),
            ("blue_background", "🔵", "Info: Neutral/Informational"),
            ("purple_background", "🟣", "Accent: Special/Featured"),
            ("gray_background", "⚫", "Subtle: Secondary/Disabled"),
        ]
    
        # Get blocks after the color palette heading
        blocks_after_heading = blocks_sorted[color_palette_heading_idx + 1:]
    
        # Find all callout blocks
        callout_blocks = [b for b in blocks_after_heading if b.get("type") == "callout"]
    
        if len(callout_blocks) < 7:
            errors.append(f"[X] Expected 7 callout blocks, found {len(callout_blocks)}")
        else:
            checks_passed.append(f"[C] Found 7 callout blocks as expected")
    
        # Validate each callout
        for i, (expected_bg, expected_icon, expected_text) in enumerate(expected_callouts):
            if i >= len(callout_blocks):
                errors.append(f"[X] Missing callout {i+1}: {expected_text}")
            else:
                checks_passed.append(f"[C] has callout {i+1}: {expected_text}")
        
            callout = callout_blocks[i]
            props = callout.get("properties", {})
            bg_color = props.get("backgroundColor", "").lower()
            icon = props.get("icon", "")
            content = callout.get("content", "")
        
            # Check background color (flexible matching)
            expected_bg_prefix = expected_bg.replace("_background", "")
            if expected_bg_prefix not in bg_color:
                errors.append(f"[X] Callout {i+1} has wrong background color: expected '{expected_bg}', found '{bg_color}'")
            else:
                checks_passed.append(f"[C] Callout {i+1} has wrong background color: expected '{expected_bg}', found '{bg_color}'")
        
            # Check icon
            if expected_icon not in icon:
                errors.append(f"[X] Callout {i+1} has wrong icon: expected '{expected_icon}', found '{icon}'")
            else:
                checks_passed.append(f"[C] Callout {i+1} has wrong icon: expected '{expected_icon}', found '{icon}'")
        
            # Check content text (case-insensitive)
            if expected_text.lower() not in content.lower():
                errors.append(f"[X] Callout {i+1} missing expected text '{expected_text}', found '{content}'")
            else:
                checks_passed.append(f"[C] Callout {i+1} has expected text '{expected_text}', found '{content}'")
    
        # 5. Check for final paragraph about consistency
        paragraph_found = False
        for block in blocks_after_heading:
            if block.get("type") == "paragraph":
                content = block.get("content", "").lower()
                if "color standards" in content and "consistency" in content:
                    paragraph_found = True
                    break
                if "use these" in content and "visual hierarchy" in content:
                    paragraph_found = True
                    break
    
        if not paragraph_found:
            errors.append("[X] Final paragraph about color standards consistency not found")
        else:
            checks_passed.append("[C] Final paragraph about color standards consistency found")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: External Resources Link Report
# =============================================================================
def _validate_agent_external_resources_link_report(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Task: Navigate to the 'External Resources & Links' page and enhance it with a comprehensive
    link validation report. After the 'Tools' heading (but before any tool bookmarks), insert
    a new heading3 '🔍 Resource Overview'. Add a callout (blue_background, icon '📊') containing
    'Total external resources: [COUNT] | Last audit: [TODAY'S DATE]'. Then create a heading3
    '📈 Resources by Category' with a bulleted list showing counts for each section. After the
    existing bookmarks, add a divider followed by heading2 '🔗 Quick Reference Matrix'. Create
    a numbered list where each item follows the format: '[NUMBER]. [Bookmark Title] - [URL Domain]
    ([Section Name])'. For example: '1. React Documentation - react.dev (Documentation)'.
    Finally, add a callout (green_background, icon '✅') with text 'All links verified and
    organized for easy access.'

    Validates:
    1. External Resources & Links page exists
    2. Heading3 '🔍 Resource Overview' exists after 'Tools' heading
    3. Blue callout with 📊 icon containing resource count and a date
    4. Heading3 '📈 Resources by Category' with bulleted list of category counts
    5. Divider after existing bookmarks
    6. Heading2 '🔗 Quick Reference Matrix'
    7. Numbered list entries with bookmark info
    8. Green callout with ✅ icon and verification message
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Find 'External Resources & Links' page using direct query
    try:
        resources_page = _find_page_by_title_direct(final_state_backend, "External Resources & Links")
        if not resources_page:
            # Also try without ampersand
            resources_page = _find_page_by_title_direct(final_state_backend, "External Resources")
        if not resources_page:
            errors.append("[X] Page 'External Resources & Links' not found")
        else:
            checks_passed.append("[C] Page 'External Resources & Links' found")
    
        page_id = resources_page.get("_id")
        if not page_id:
            errors.append("[X] External Resources & Links page has no _id")
        else:
            checks_passed.append("[C] External Resources & Links page has _id")
    
        # Get blocks for this page using direct query
        blocks = _get_blocks_for_page_direct(final_state_backend, page_id)
        blocks_sorted = sorted(blocks, key=lambda b: b.get("order", 0))
    
        if not blocks_sorted:
            errors.append("[X] External Resources & Links page has no content blocks")
        else:
            checks_passed.append("[C] External Resources & Links page has content blocks")
    
        # 2. Find 'Tools' heading
        tools_heading_idx = -1
        for idx, block in enumerate(blocks_sorted):
            if block.get("type") == "heading2":
                content = block.get("content", "").lower()
                if "tools" in content:
                    tools_heading_idx = idx
                    break
    
        if tools_heading_idx == -1:
            errors.append("[X] Heading2 'Tools' not found")
        else:
            checks_passed.append("[C] Heading2 'Tools' found")
    
        # 3. Find heading3 '🔍 Resource Overview' after Tools heading
        resource_overview_found = False
        for idx in range(tools_heading_idx + 1, len(blocks_sorted)):
            block = blocks_sorted[idx]
            if block.get("type") == "heading3":
                content = block.get("content", "")
                if "🔍" in content and "resource overview" in content.lower():
                    resource_overview_found = True
                    break
            # Stop if we hit another heading2 without finding it
            if block.get("type") == "heading2":
                break
    
        if not resource_overview_found:
            errors.append("[X] Heading3 '🔍 Resource Overview' not found after 'Tools' heading")
        else:
            checks_passed.append("[C] Heading3 '🔍 Resource Overview' found after 'Tools' heading")
    
        # 4. Find blue callout with 📊 icon containing count and date
        blue_callout_found = False
        for block in blocks_sorted:
            if block.get("type") == "callout":
                props = block.get("properties", {})
                bg_color = props.get("backgroundColor", "").lower()
                icon = props.get("icon", "")
                content = block.get("content", "").lower()
            
                if "blue" in bg_color and "📊" in icon:
                    if "total external resources" in content or "total resources" in content:
                        # Check for any date pattern (flexible)
                        if "audit" in content or re.search(r'\d{1,4}[-/]\d{1,2}[-/]\d{1,4}|\d{1,2}\s+\w+\s+\d{4}|\w+\s+\d{1,2},?\s+\d{4}', content):
                            blue_callout_found = True
                            break
    
        if not blue_callout_found:
            errors.append("[X] Blue callout with 📊 icon containing resource count and audit date not found")
        else:
            checks_passed.append("[C] Blue callout with 📊 icon containing resource count and audit date found")
    
        # 5. Find heading3 '📈 Resources by Category'
        category_heading_found = False
        for block in blocks_sorted:
            if block.get("type") == "heading3":
                content = block.get("content", "")
                if "📈" in content and "resources by category" in content.lower():
                    category_heading_found = True
                    break
    
        if not category_heading_found:
            errors.append("[X] Heading3 '📈 Resources by Category' not found")
        else:
            checks_passed.append("[C] Heading3 '📈 Resources by Category' found")
    
        # 6. Find heading2 '🔗 Quick Reference Matrix'
        matrix_heading_found = False
        for block in blocks_sorted:
            if block.get("type") == "heading2":
                content = block.get("content", "")
                if "🔗" in content and "quick reference matrix" in content.lower():
                    matrix_heading_found = True
                    break
    
        if not matrix_heading_found:
            errors.append("[X] Heading2 '🔗 Quick Reference Matrix' not found")
        else:
            checks_passed.append("[C] Heading2 '🔗 Quick Reference Matrix' found")
    
        # 7. Check for numbered list entries
        numbered_list_blocks = [b for b in blocks_sorted if b.get("type") == "numberedList"]
        if len(numbered_list_blocks) < 1:
            errors.append("[X] No numbered list entries found for Quick Reference Matrix")
        else:
            checks_passed.append("[C] numbered list entries found for Quick Reference Matrix")
    
        # 8. Find green callout with ✅ icon
        green_callout_found = False
        for block in blocks_sorted:
            if block.get("type") == "callout":
                props = block.get("properties", {})
                bg_color = props.get("backgroundColor", "").lower()
                icon = props.get("icon", "")
                content = block.get("content", "").lower()
            
                if "green" in bg_color and "✅" in icon:
                    if "verified" in content or "links verified" in content or "organized" in content:
                        green_callout_found = True
                        break
    
        if not green_callout_found:
            errors.append("[X] Green callout with ✅ icon and verification message not found")
        else:
            checks_passed.append("[C] Green callout with ✅ icon and verification message found")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: Feature Requests Voting System
# =============================================================================
def _validate_agent_feature_requests_voting_system(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Task: In the 'Feature Requests' page, implement a voting system visualization and reorganize content.
    First, move the 'Community Suggestions' section to appear immediately AFTER the main description
    paragraph but BEFORE 'High Priority'. Then, in the High Priority section, after each to-do item,
    add a paragraph in italic text showing vote counts: for 'Dark mode support' add '_Votes: 1,234 users_',
    for 'Keyboard shortcuts customization' add '_Votes: 987 users_', for 'Export to PDF functionality'
    add '_Votes: 756 users_'. Next, add a new section at the very end of the page: divider, heading_2
    '📊 Feature Request Analytics', then a callout (purple_background, icon '📈') with text
    'Total feature requests: 6 | Total votes: 3,421 | Average votes per feature: 570'. Finally,
    add an image block with URL 'https://charts.company.com/feature-votes.png' and caption
    'Feature request trends - Q4 2023'.

    Validates:
    1. Feature Requests page exists
    2. 'Community Suggestions' section appears after description but before 'High Priority'
    3. Italic vote count paragraphs after each High Priority todo
    4. Divider and heading2 '📊 Feature Request Analytics' at end
    5. Purple callout with 📈 icon containing analytics text
    6. Image block with specific URL and caption
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Find 'Feature Requests' page using direct query
    try:
        feature_requests_page = _find_page_by_title_direct(final_state_backend, "Feature Requests")
        if not feature_requests_page:
            errors.append("[X] Page 'Feature Requests' not found")
        else:
            checks_passed.append("[C] Page 'Feature Requests' found")
    
        page_id = feature_requests_page.get("_id")
        if not page_id:
            errors.append("[X] Feature Requests page has no _id")
        else:
            checks_passed.append("[C] Feature Requests page has _id")
    
        # Get blocks for this page using direct query
        blocks = _get_blocks_for_page_direct(final_state_backend, page_id)
        blocks_sorted = sorted(blocks, key=lambda b: b.get("order", 0))
    
        if not blocks_sorted:
            errors.append("[X] Feature Requests page has no content blocks")
        else:
            checks_passed.append("[C] Feature Requests page has content blocks")
    
        # Find key sections by their order positions
        description_idx = -1
        community_suggestions_idx = -1
        high_priority_idx = -1
    
        for idx, block in enumerate(blocks_sorted):
            block_type = block.get("type", "")
            content = block.get("content", "").lower()
        
            # Find description paragraph (contains "community requested" or similar)
            if block_type == "paragraph" and description_idx == -1:
                if "community requested" in content or "feature" in content:
                    description_idx = idx
        
            # Find Community Suggestions heading
            if block_type == "heading2" and "community suggestions" in content:
                community_suggestions_idx = idx
        
            # Find High Priority heading
            if block_type == "heading2" and "high priority" in content:
                high_priority_idx = idx
    
        # 2. Validate Community Suggestions appears after description but before High Priority
        if community_suggestions_idx == -1:
            errors.append("[X] 'Community Suggestions' heading not found")
        else:
            checks_passed.append("[C] 'Community Suggestions' heading found")
        if high_priority_idx == -1:
            errors.append("[X] 'High Priority' heading not found")
        else:
            checks_passed.append("[C] 'High Priority' heading found")
        if description_idx == -1:
            errors.append("[X] Description paragraph not found")
        else:
            checks_passed.append("[C] Description paragraph found")
    
        if not (description_idx < community_suggestions_idx < high_priority_idx):
            errors.append(f"[X] 'Community Suggestions' section not positioned between description (order {description_idx}) and 'High Priority' (order {high_priority_idx}). Found at order {community_suggestions_idx}")
        else:
            checks_passed.append(f"[C] 'Community Suggestions' section positioned between description (order {description_idx}) and 'High Priority' (order {high_priority_idx}). Found at order {community_suggestions_idx}")
    
        # 3. Check for italic vote count paragraphs after High Priority todos
        vote_counts = {
            "dark mode": "1,234",
            "keyboard shortcuts": "987",
            "export to pdf": "756"
        }
    
        votes_found = 0
        for idx in range(high_priority_idx + 1, len(blocks_sorted)):
            block = blocks_sorted[idx]
            # Stop if we hit another heading2
            if block.get("type") == "heading2" and "high priority" not in block.get("content", "").lower():
                break
        
            if block.get("type") == "paragraph":
                content = block.get("content", "")
                props = block.get("properties", {})
            
                # Check for vote counts with italic formatting
                for feature, count in vote_counts.items():
                    if count in content and "votes" in content.lower():
                        # Check for italic (markdown or property)
                        if _check_text_is_italic(content, props) or count in content:
                            votes_found += 1
                            break
    
        if votes_found < 3:
            errors.append(f"[X] Only found {votes_found} vote count paragraphs, expected 3")
        else:
            checks_passed.append(f"[C] Only found {votes_found} vote count paragraphs, expected 3")
    
        # 4. Find heading2 '📊 Feature Request Analytics'
        analytics_heading_found = False
        analytics_heading_idx = -1
        for idx, block in enumerate(blocks_sorted):
            if block.get("type") == "heading2":
                content = block.get("content", "")
                if "📊" in content and "feature request analytics" in content.lower():
                    analytics_heading_found = True
                    analytics_heading_idx = idx
                    break
    
        if not analytics_heading_found:
            errors.append("[X] Heading2 '📊 Feature Request Analytics' not found")
        else:
            checks_passed.append("[C] Heading2 '📊 Feature Request Analytics' found")
    
        # 5. Check for divider before analytics heading
        divider_before_analytics = False
        for idx in range(analytics_heading_idx - 1, -1, -1):
            if blocks_sorted[idx].get("type") == "divider":
                divider_before_analytics = True
                break
            # Allow some blocks between divider and heading
            if blocks_sorted[idx].get("type") == "heading2":
                break
    
        if not divider_before_analytics:
            errors.append("[X] Divider not found before '📊 Feature Request Analytics' section")
        else:
            checks_passed.append("[C] Divider found before '📊 Feature Request Analytics' section")
    
        # 6. Find purple callout with 📈 icon
        purple_callout_found = False
        for block in blocks_sorted:
            if block.get("type") == "callout":
                props = block.get("properties", {})
                bg_color = props.get("backgroundColor", "").lower()
                icon = props.get("icon", "")
                content = block.get("content", "")
            
                if "purple" in bg_color and "📈" in icon:
                    if "total feature requests" in content.lower() or "total votes" in content.lower():
                        if "3,421" in content or "3421" in content:
                            purple_callout_found = True
                            break
    
        if not purple_callout_found:
            errors.append("[X] Purple callout with 📈 icon and analytics data not found")
        else:
            checks_passed.append("[C] Purple callout with 📈 icon and analytics data found")
    
        # 7. Find image block with specific URL
        image_found = False
        for block in blocks_sorted:
            if block.get("type") == "image":
                props = block.get("properties", {})
                url = props.get("url", "")
                caption = props.get("caption", "")
            
                if "feature-votes" in url.lower() or "charts.company.com" in url.lower():
                    if "q4 2023" in caption.lower() or "feature request" in caption.lower():
                        image_found = True
                        break
    
        if not image_found:
            errors.append("[X] Image block with feature votes URL and Q4 2023 caption not found")
        else:
            checks_passed.append("[C] Image block with feature votes URL and Q4 2023 caption found")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: Engineering Wiki API Endpoints
# =============================================================================
def _validate_agent_engineering_wiki_api_endpoints(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Task: On the 'Engineering Wiki' page, add a detailed 'API Endpoints' section with precise
    formatting. Insert this new content immediately AFTER any existing numbered lists but BEFORE
    any heading_2 blocks. Structure as: heading_2 '🔌 API Endpoints', then heading_3 '🟢 Public Endpoints',
    followed by a code block with language 'javascript' containing exactly:
    'GET /api/v1/users\\nGET /api/v1/products\\nGET /api/v1/search'. Add a paragraph
    'Rate limit: 100 requests per minute'. Then add heading_3 '🔒 Protected Endpoints', another
    code block with language 'javascript' containing:
    'POST /api/v1/users\\nPUT /api/v1/users/:id\\nDELETE /api/v1/products/:id'. Below this,
    add a callout with red_background, icon '🔐', text 'Authentication required: Bearer token
    must be included in Authorization header.'

    Validates:
    1. Engineering Wiki page exists
    2. Heading2 '🔌 API Endpoints' exists
    3. Heading3 '🟢 Public Endpoints' exists
    4. Code block with javascript language and GET endpoints
    5. Paragraph with rate limit text
    6. Heading3 '🔒 Protected Endpoints' exists
    7. Code block with javascript language and POST/PUT/DELETE endpoints
    8. Red callout with 🔐 icon and authentication text
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Find 'Engineering Wiki' page using direct query
    try:
        wiki_page = _find_page_by_title_direct(final_state_backend, "Engineering Wiki")
        if not wiki_page:
            errors.append("[X] Page 'Engineering Wiki' not found")
        else:
            checks_passed.append("[C] Page 'Engineering Wiki' found")
    
        page_id = wiki_page.get("_id")
        if not page_id:
            errors.append("[X] Engineering Wiki page has no _id")
        else:
            checks_passed.append("[C] Engineering Wiki page has _id")
    
        # Get blocks for this page using direct query
        blocks = _get_blocks_for_page_direct(final_state_backend, page_id)
        blocks_sorted = sorted(blocks, key=lambda b: b.get("order", 0))
    
        if not blocks_sorted:
            errors.append("[X] Engineering Wiki page has no content blocks")
        else:
            checks_passed.append("[C] Engineering Wiki page has content blocks")
    
        # 2. Find heading2 '🔌 API Endpoints'
        api_endpoints_heading_found = False
        api_endpoints_idx = -1
        for idx, block in enumerate(blocks_sorted):
            if block.get("type") == "heading2":
                content = block.get("content", "")
                if "🔌" in content and "api endpoints" in content.lower():
                    api_endpoints_heading_found = True
                    api_endpoints_idx = idx
                    break
    
        if not api_endpoints_heading_found:
            errors.append("[X] Heading2 '🔌 API Endpoints' not found")
        else:
            checks_passed.append("[C] Heading2 '🔌 API Endpoints' found")
    
        # 3. Find heading3 '🟢 Public Endpoints'
        public_endpoints_found = False
        for block in blocks_sorted:
            if block.get("type") == "heading3":
                content = block.get("content", "")
                if "🟢" in content and "public endpoints" in content.lower():
                    public_endpoints_found = True
                    break
    
        if not public_endpoints_found:
            errors.append("[X] Heading3 '🟢 Public Endpoints' not found")
        else:
            checks_passed.append("[C] Heading3 '🟢 Public Endpoints' found")
    
        # 4. Find code block with javascript and GET endpoints
        public_code_found = False
        for block in blocks_sorted:
            if block.get("type") == "code":
                props = block.get("properties", {})
                language = props.get("language", "").lower()
                content = block.get("content", "")
            
                if "javascript" in language or "js" in language:
                    if "GET /api/v1/users" in content and "GET /api/v1/products" in content and "GET /api/v1/search" in content:
                        public_code_found = True
                        break
    
        if not public_code_found:
            errors.append("[X] Code block with javascript language and public GET endpoints not found")
        else:
            checks_passed.append("[C] Code block with javascript language and public GET endpoints found")
    
        # 5. Find paragraph with rate limit
        rate_limit_found = False
        for block in blocks_sorted:
            if block.get("type") == "paragraph":
                content = block.get("content", "").lower()
                if "rate limit" in content and "100" in content:
                    rate_limit_found = True
                    break
    
        if not rate_limit_found:
            errors.append("[X] Paragraph with rate limit text not found")
        else:
            checks_passed.append("[C] Paragraph with rate limit text found")
    
        # 6. Find heading3 '🔒 Protected Endpoints'
        protected_endpoints_found = False
        for block in blocks_sorted:
            if block.get("type") == "heading3":
                content = block.get("content", "")
                if "🔒" in content and "protected endpoints" in content.lower():
                    protected_endpoints_found = True
                    break
    
        if not protected_endpoints_found:
            errors.append("[X] Heading3 '🔒 Protected Endpoints' not found")
        else:
            checks_passed.append("[C] Heading3 '🔒 Protected Endpoints' found")
    
        # 7. Find code block with javascript and POST/PUT/DELETE endpoints
        protected_code_found = False
        for block in blocks_sorted:
            if block.get("type") == "code":
                props = block.get("properties", {})
                language = props.get("language", "").lower()
                content = block.get("content", "")
            
                if "javascript" in language or "js" in language:
                    if "POST /api/v1/users" in content and "PUT /api/v1/users" in content and "DELETE /api/v1/products" in content:
                        protected_code_found = True
                        break
    
        if not protected_code_found:
            errors.append("[X] Code block with javascript language and protected POST/PUT/DELETE endpoints not found")
        else:
            checks_passed.append("[C] Code block with javascript language and protected POST/PUT/DELETE endpoints found")
    
        # 8. Find red callout with 🔐 icon
        auth_callout_found = False
        for block in blocks_sorted:
            if block.get("type") == "callout":
                props = block.get("properties", {})
                bg_color = props.get("backgroundColor", "").lower()
                icon = props.get("icon", "")
                content = block.get("content", "").lower()
            
                if "red" in bg_color and "🔐" in icon:
                    if "authentication required" in content or "bearer token" in content or "authorization header" in content:
                        auth_callout_found = True
                        break
    
        if not auth_callout_found:
            errors.append("[X] Red callout with 🔐 icon and authentication requirement text not found")
        else:
            checks_passed.append("[C] Red callout with 🔐 icon and authentication requirement text found")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: Meeting Notes Index
# =============================================================================
def _validate_agent_meeting_notes_index(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Task: On the 'Meeting Notes' page, add a comprehensive meeting index. First, count all child
    pages that contain 'Sprint' in their title. At the beginning of the Meeting Notes page
    (after the title but before any existing content), add a heading_2 '📅 Meeting Quick Stats'
    with a paragraph: 'Total meetings documented: [X]' where X is the total number of child pages.
    Add another paragraph: 'Sprint-related meetings: [Y]' where Y is the count of pages with 'Sprint'
    in the title. Then add a divider, followed by heading_2 '🏷️ Meeting Categories'. Create
    heading_3 '🔄 Sprint Meetings' and list all pages with 'Sprint' in the title as a numbered
    list with format: '[number]. [icon] [title] - [createdAt date]'. Add another heading_3
    '📝 Other Meetings' and list remaining child pages in the same format. End with a callout
    having green_background and icon '✅' containing: 'All meetings are properly categorized and indexed.'

    Validates:
    1. Meeting Notes page exists
    2. Heading2 '📅 Meeting Quick Stats' at beginning
    3. Paragraph with total meetings count
    4. Paragraph with Sprint-related meetings count
    5. Divider after quick stats
    6. Heading2 '🏷️ Meeting Categories'
    7. Heading3 '🔄 Sprint Meetings' with numbered list
    8. Heading3 '📝 Other Meetings' with numbered list
    9. Green callout with ✅ icon and categorization message
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Find 'Meeting Notes' page using direct query
    try:
        meeting_pages = _find_pages_by_title_direct(final_state_backend, "Meeting Notes")
        if not meeting_pages:
            errors.append("[X] Page 'Meeting Notes' not found")
        else:
            checks_passed.append("[C] Page 'Meeting Notes' found")
    
        # Use the first one found
        meeting_notes_page = meeting_pages[0]
        page_id = meeting_notes_page.get("_id")
        if not page_id:
            errors.append("[X] Meeting Notes page has no _id")
        else:
            checks_passed.append("[C] Meeting Notes page has _id")
    
        # Count child pages using direct query
        child_pages = _get_child_pages_direct(final_state_backend, page_id)
        total_child_count = len(child_pages)
        sprint_pages = [p for p in child_pages if "sprint" in p.get("title", "").lower()]
        sprint_count = len(sprint_pages)
    
        # Get blocks for this page using direct query
        blocks = _get_blocks_for_page_direct(final_state_backend, page_id)
        blocks_sorted = sorted(blocks, key=lambda b: b.get("order", 0))
    
        if not blocks_sorted:
            errors.append("[X] Meeting Notes page has no content blocks")
        else:
            checks_passed.append("[C] Meeting Notes page has content blocks")
    
        # 2. Find heading2 '📅 Meeting Quick Stats'
        quick_stats_found = False
        quick_stats_idx = -1
        for idx, block in enumerate(blocks_sorted):
            if block.get("type") == "heading2":
                content = block.get("content", "")
                if "📅" in content and "meeting quick stats" in content.lower():
                    quick_stats_found = True
                    quick_stats_idx = idx
                    break
    
        if not quick_stats_found:
            errors.append("[X] Heading2 '📅 Meeting Quick Stats' not found")
        else:
            checks_passed.append("[C] Heading2 '📅 Meeting Quick Stats' found")
    
        # 3. Find paragraph with total meetings count
        total_count_found = False
        for block in blocks_sorted:
            if block.get("type") == "paragraph":
                content = block.get("content", "").lower()
                if "total meetings documented" in content or "total meetings" in content:
                    total_count_found = True
                    break
    
        if not total_count_found:
            errors.append("[X] Paragraph with total meetings count not found")
        else:
            checks_passed.append("[C] Paragraph with total meetings count found")
    
        # 4. Find paragraph with Sprint-related meetings count
        sprint_count_found = False
        for block in blocks_sorted:
            if block.get("type") == "paragraph":
                content = block.get("content", "").lower()
                if "sprint-related" in content or "sprint meetings" in content:
                    sprint_count_found = True
                    break
    
        if not sprint_count_found:
            errors.append("[X] Paragraph with Sprint-related meetings count not found")
        else:
            checks_passed.append("[C] Paragraph with Sprint-related meetings count found")
    
        # 5. Find divider
        divider_found = False
        for block in blocks_sorted:
            if block.get("type") == "divider":
                divider_found = True
                break
    
        if not divider_found:
            errors.append("[X] Divider not found after quick stats")
        else:
            checks_passed.append("[C] Divider found after quick stats")
    
        # 6. Find heading2 '🏷️ Meeting Categories'
        categories_heading_found = False
        for block in blocks_sorted:
            if block.get("type") == "heading2":
                content = block.get("content", "")
                if "🏷️" in content and "meeting categories" in content.lower():
                    categories_heading_found = True
                    break
    
        if not categories_heading_found:
            errors.append("[X] Heading2 '🏷️ Meeting Categories' not found")
        else:
            checks_passed.append("[C] Heading2 '🏷️ Meeting Categories' found")
    
        # 7. Find heading3 '🔄 Sprint Meetings'
        sprint_heading_found = False
        for block in blocks_sorted:
            if block.get("type") == "heading3":
                content = block.get("content", "")
                if "🔄" in content and "sprint meetings" in content.lower():
                    sprint_heading_found = True
                    break
    
        if not sprint_heading_found:
            errors.append("[X] Heading3 '🔄 Sprint Meetings' not found")
        else:
            checks_passed.append("[C] Heading3 '🔄 Sprint Meetings' found")
    
        # 8. Find heading3 '📝 Other Meetings'
        other_heading_found = False
        for block in blocks_sorted:
            if block.get("type") == "heading3":
                content = block.get("content", "")
                if "📝" in content and "other meetings" in content.lower():
                    other_heading_found = True
                    break
    
        if not other_heading_found:
            errors.append("[X] Heading3 '📝 Other Meetings' not found")
        else:
            checks_passed.append("[C] Heading3 '📝 Other Meetings' found")
    
        # 9. Check for numbered lists
        numbered_lists = [b for b in blocks_sorted if b.get("type") == "numberedList"]
        if len(numbered_lists) < 1:
            errors.append("[X] No numbered list entries found for meeting lists")
        else:
            checks_passed.append("[C] numbered list entries found for meeting lists")
    
        # 10. Find green callout with ✅ icon
        green_callout_found = False
        for block in blocks_sorted:
            if block.get("type") == "callout":
                props = block.get("properties", {})
                bg_color = props.get("backgroundColor", "").lower()
                icon = props.get("icon", "")
                content = block.get("content", "").lower()
            
                if "green" in bg_color and "✅" in icon:
                    if "categorized" in content or "indexed" in content:
                        green_callout_found = True
                        break
    
        if not green_callout_found:
            errors.append("[X] Green callout with ✅ icon and categorization message not found")
        else:
            checks_passed.append("[C] Green callout with ✅ icon and categorization message found")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: Deployment Readiness Dashboard
# =============================================================================
def _validate_agent_deployment_readiness_dashboard(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Task: Create a 'Deployment Readiness Dashboard' as a child page under 'Deployment Guide'.
    First fetch the 'CI/CD Pipeline' page (child of Deployment Guide) and analyze its content.
    Structure the dashboard with: heading_1 '🚀 Deployment Readiness Dashboard', heading_2
    '⚡ Pipeline Status' with content extracted from CI/CD Pipeline page - count all todo blocks
    and create a paragraph 'Pipeline tasks: [X] completed, [Y] pending ([Z]% ready)'. Add
    heading_2 '🔒 Security Checklist' with five new todo blocks (all unchecked):
    '☐ Security scan passed on latest build', '☐ Secrets rotation completed',
    '☐ Access controls reviewed', '☐ Backup procedures tested', '☐ Rollback plan documented'.
    Then add heading_2 '📋 Pre-Deployment Verification' with a numbered list: '1. Code freeze
    status: [Add callout with yellow_background "⏸️ Code freeze active" if today is Friday-Sunday,
    otherwise green_background "✅ Deployments allowed"]', '2. Team availability: [Add paragraph
    "Ensure 2+ engineers on-call"]', '3. Monitoring alerts: [Add paragraph "All dashboards green"]'.
    Finally, add heading_2 '🎯 Go/No-Go Decision' with a callout that has red_background and text
    '🛑 NOT READY for deployment' if pipeline ready % < 80 OR any security todo would be unchecked
    OR today is weekend, otherwise green_background with text '✅ READY for deployment'.

    Validates:
    1. Deployment Guide page exists
    2. New child page 'Deployment Readiness Dashboard' exists under Deployment Guide
    3. Heading1 '🚀 Deployment Readiness Dashboard'
    4. Heading2 '⚡ Pipeline Status' with paragraph about pipeline tasks
    5. Heading2 '🔒 Security Checklist' with 5 unchecked todo blocks
    6. Heading2 '📋 Pre-Deployment Verification' with numbered list and callouts/paragraphs
    7. Heading2 '🎯 Go/No-Go Decision' with appropriate callout (accept either red or green)
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Find 'Deployment Guide' page using direct query
    try:
        deployment_guide_page = _find_page_by_title_direct(final_state_backend, "Deployment Guide")
        if not deployment_guide_page:
            errors.append("[X] Page 'Deployment Guide' not found")
        else:
            checks_passed.append("[C] Page 'Deployment Guide' found")
    
        deployment_guide_id = deployment_guide_page.get("_id")
    
        # 2. Find 'Deployment Readiness Dashboard' as child of Deployment Guide using direct query
        child_pages = _get_child_pages_direct(final_state_backend, deployment_guide_id)
        dashboard_page = None
        for page in child_pages:
            title = page.get("title", "").lower()
            if "deployment readiness dashboard" in title or "readiness dashboard" in title:
                dashboard_page = page
                break
    
        if not dashboard_page:
            errors.append("[X] Child page 'Deployment Readiness Dashboard' not found under 'Deployment Guide'")
        else:
            checks_passed.append("[C] Child page 'Deployment Readiness Dashboard' found under 'Deployment Guide'")
    
        dashboard_id = dashboard_page.get("_id")
        if not dashboard_id:
            errors.append("[X] Deployment Readiness Dashboard page has no _id")
        else:
            checks_passed.append("[C] Deployment Readiness Dashboard page has _id")
    
        # Get blocks for the dashboard page using direct query
        blocks = _get_blocks_for_page_direct(final_state_backend, dashboard_id)
        blocks_sorted = sorted(blocks, key=lambda b: b.get("order", 0))
    
        if not blocks_sorted:
            errors.append("[X] Deployment Readiness Dashboard page has no content blocks")
        else:
            checks_passed.append("[C] Deployment Readiness Dashboard page has content blocks")
    
        # 3. Find heading1 '🚀 Deployment Readiness Dashboard'
        main_heading_found = False
        for block in blocks_sorted:
            if block.get("type") == "heading1":
                content = block.get("content", "")
                if "🚀" in content and "deployment readiness dashboard" in content.lower():
                    main_heading_found = True
                    break
    
        if not main_heading_found:
            errors.append("[X] Heading1 '🚀 Deployment Readiness Dashboard' not found")
        else:
            checks_passed.append("[C] Heading1 '🚀 Deployment Readiness Dashboard' found")
    
        # 4. Find heading2 '⚡ Pipeline Status'
        pipeline_heading_found = False
        for block in blocks_sorted:
            if block.get("type") == "heading2":
                content = block.get("content", "")
                if "⚡" in content and "pipeline status" in content.lower():
                    pipeline_heading_found = True
                    break
    
        if not pipeline_heading_found:
            errors.append("[X] Heading2 '⚡ Pipeline Status' not found")
        else:
            checks_passed.append("[C] Heading2 '⚡ Pipeline Status' found")
    
        # Check for paragraph about pipeline tasks
        pipeline_paragraph_found = False
        for block in blocks_sorted:
            if block.get("type") == "paragraph":
                content = block.get("content", "").lower()
                if "pipeline tasks" in content or ("completed" in content and "pending" in content):
                    pipeline_paragraph_found = True
                    break
    
        if not pipeline_paragraph_found:
            errors.append("[X] Paragraph with pipeline tasks status not found")
        else:
            checks_passed.append("[C] Paragraph with pipeline tasks status found")
    
        # 5. Find heading2 '🔒 Security Checklist'
        security_heading_found = False
        for block in blocks_sorted:
            if block.get("type") == "heading2":
                content = block.get("content", "")
                if "🔒" in content and "security checklist" in content.lower():
                    security_heading_found = True
                    break
    
        if not security_heading_found:
            errors.append("[X] Heading2 '🔒 Security Checklist' not found")
        else:
            checks_passed.append("[C] Heading2 '🔒 Security Checklist' found")
    
        # Check for 5 security todo blocks
        security_todos = []
        security_keywords = ["security scan", "secrets rotation", "access controls", "backup procedures", "rollback plan"]
    
        for block in blocks_sorted:
            if block.get("type") == "todo":
                content = block.get("content", "").lower()
                for keyword in security_keywords:
                    if keyword in content:
                        security_todos.append(block)
                        break
    
        if len(security_todos) < 5:
            errors.append(f"[X] Expected 5 security checklist todo blocks, found {len(security_todos)}")
        else:
            checks_passed.append(f"[C] Found 5 security checklist todo blocks as expected")
    
        # 6. Find heading2 '📋 Pre-Deployment Verification'
        verification_heading_found = False
        for block in blocks_sorted:
            if block.get("type") == "heading2":
                content = block.get("content", "")
                if "📋" in content and "pre-deployment verification" in content.lower():
                    verification_heading_found = True
                    break
    
        if not verification_heading_found:
            errors.append("[X] Heading2 '📋 Pre-Deployment Verification' not found")
        else:
            checks_passed.append("[C] Heading2 '📋 Pre-Deployment Verification' found")
    
        # Check for numbered list or relevant content
        numbered_list_found = False
        for block in blocks_sorted:
            if block.get("type") == "numberedList":
                numbered_list_found = True
                break
    
        if not numbered_list_found:
            errors.append("[X] No numbered list found in Pre-Deployment Verification section")
        else:
            checks_passed.append("[C] numbered list found in Pre-Deployment Verification section")
    
        # 7. Find heading2 '🎯 Go/No-Go Decision'
        decision_heading_found = False
        for block in blocks_sorted:
            if block.get("type") == "heading2":
                content = block.get("content", "")
                if "🎯" in content and "go/no-go" in content.lower():
                    decision_heading_found = True
                    break
    
        if not decision_heading_found:
            errors.append("[X] Heading2 '🎯 Go/No-Go Decision' not found")
        else:
            checks_passed.append("[C] Heading2 '🎯 Go/No-Go Decision' found")
    
        # Check for decision callout (accept either red or green based on conditions)
        decision_callout_found = False
        for block in blocks_sorted:
            if block.get("type") == "callout":
                props = block.get("properties", {})
                bg_color = props.get("backgroundColor", "").lower()
                content = block.get("content", "").lower()
            
                # Accept either NOT READY (red) or READY (green)
                if ("red" in bg_color and ("not ready" in content or "🛑" in block.get("content", ""))) or \
                   ("green" in bg_color and ("ready" in content or "✅" in block.get("content", ""))):
                    decision_callout_found = True
                    break
    
        if not decision_callout_found:
            errors.append("[X] Go/No-Go Decision callout with appropriate status not found")
        else:
            checks_passed.append("[C] Go/No-Go Decision callout with appropriate status found")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: Comprehensive PRD Callout and Implementation Roadmap
# =============================================================================
def _validate_agent_prd_callout_implementation_roadmap(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Task: Navigate to 'Comprehensive Product Requirements Document' page. This page has many
    sections with 'Overview' headings at different levels. Perform these precise edits:
    1) Find the heading3 'Overview - Part 2' and the paragraph immediately following it that
    starts with 'Detailed description for Overview part 2'. Insert a callout between this heading
    and paragraph with orange_background, icon '🔔', text 'Critical: This section requires
    stakeholder approval before implementation'.
    2) Locate all bulletedList items that contain 'Key point 2' and update their text to
    '⭐ Key point 2 for [SECTION]' where [SECTION] is the heading2 text that precedes them.
    3) After the last 'Overview - Part 3' section, add a new heading2 'Implementation Roadmap'
    with a divider above it. Under this new heading, add three todo blocks:
    '📅 Technical design review - Week 1', '🛠️ Development sprint - Weeks 2-4',
    '✅ QA and deployment - Week 5'.

    Validates:
    1. Comprehensive Product Requirements Document page exists
    2. Orange callout with 🔔 icon positioned between 'Overview - Part 2' heading and its paragraph
    3. Callout contains stakeholder approval text
    4. 'Key point 2' bullets updated with ⭐ emoji and section name
    5. Divider followed by heading2 'Implementation Roadmap' after Overview Part 3
    6. Three todo blocks with exact text and emojis
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Find 'Comprehensive Product Requirements Document' page using direct query
    try:
        prd_page = _find_page_by_title_direct(final_state_backend, "Comprehensive Product Requirements Document")
        if not prd_page:
            errors.append("[X] Page 'Comprehensive Product Requirements Document' not found")
        else:
            checks_passed.append("[C] Page 'Comprehensive Product Requirements Document' found")
    
        page_id = prd_page.get("_id")
        if not page_id:
            errors.append("[X] Comprehensive Product Requirements Document page has no _id")
        else:
            checks_passed.append("[C] Comprehensive Product Requirements Document page has _id")
    
        # Get blocks for this page using direct query
        blocks = _get_blocks_for_page_direct(final_state_backend, page_id)
        blocks_sorted = sorted(blocks, key=lambda b: b.get("order", 0))
    
        if not blocks_sorted:
            errors.append("[X] Comprehensive Product Requirements Document page has no content blocks")
        else:
            checks_passed.append("[C] Comprehensive Product Requirements Document page has content blocks")
    
        # 2. Find 'Overview - Part 2' heading and check for callout after it
        overview_part2_idx = -1
        for idx, block in enumerate(blocks_sorted):
            if block.get("type") == "heading3":
                content = block.get("content", "").lower()
                if "overview - part 2" in content or "overview part 2" in content:
                    overview_part2_idx = idx
                    break
    
        if overview_part2_idx == -1:
            errors.append("[X] Heading3 'Overview - Part 2' not found")
        else:
            checks_passed.append("[C] Heading3 'Overview - Part 2' found")
    
        # 3. Check for orange callout with 🔔 icon after Overview Part 2 heading
        orange_callout_found = False
        for idx in range(overview_part2_idx + 1, min(overview_part2_idx + 5, len(blocks_sorted))):
            block = blocks_sorted[idx]
            if block.get("type") == "callout":
                props = block.get("properties", {})
                bg_color = props.get("backgroundColor", "").lower()
                icon = props.get("icon", "")
                content = block.get("content", "").lower()
            
                if "orange" in bg_color and "🔔" in icon:
                    if "stakeholder approval" in content or "critical" in content:
                        orange_callout_found = True
                        break
    
        if not orange_callout_found:
            errors.append("[X] Orange callout with 🔔 icon containing stakeholder approval text not found after 'Overview - Part 2'")
        else:
            checks_passed.append("[C] Orange callout with 🔔 icon containing stakeholder approval text found after 'Overview - Part 2'")
    
        # 4. Check that 'Key point 2' bullets are updated with ⭐ emoji
        key_point_2_updated = 0
        for block in blocks_sorted:
            if block.get("type") == "bulletedList":
                content = block.get("content", "")
                if "⭐" in content and "key point 2" in content.lower():
                    key_point_2_updated += 1
    
        if key_point_2_updated < 1:
            errors.append("[X] No 'Key point 2' bullets found with ⭐ emoji update")
        else:
            checks_passed.append("[C] 'Key point 2' bullets found with ⭐ emoji update")
    
        # 5. Find heading2 'Implementation Roadmap'
        roadmap_heading_found = False
        roadmap_heading_idx = -1
        for idx, block in enumerate(blocks_sorted):
            if block.get("type") == "heading2":
                content = block.get("content", "").lower()
                if "implementation roadmap" in content:
                    roadmap_heading_found = True
                    roadmap_heading_idx = idx
                    break
    
        if not roadmap_heading_found:
            errors.append("[X] Heading2 'Implementation Roadmap' not found")
        else:
            checks_passed.append("[C] Heading2 'Implementation Roadmap' found")
    
        # Check for divider before roadmap heading
        divider_before_roadmap = False
        for idx in range(roadmap_heading_idx - 1, max(roadmap_heading_idx - 5, -1), -1):
            if blocks_sorted[idx].get("type") == "divider":
                divider_before_roadmap = True
                break
    
        if not divider_before_roadmap:
            errors.append("[X] Divider not found before 'Implementation Roadmap' heading")
        else:
            checks_passed.append("[C] Divider found before 'Implementation Roadmap' heading")
    
        # 6. Check for 3 todo blocks with specific text
        roadmap_todos = {
            "technical design review": False,
            "development sprint": False,
            "qa and deployment": False
        }
    
        for block in blocks_sorted:
            if block.get("type") == "todo":
                content = block.get("content", "").lower()
                if "📅" in block.get("content", "") and "technical design review" in content:
                    roadmap_todos["technical design review"] = True
                elif "🛠️" in block.get("content", "") and "development sprint" in content:
                    roadmap_todos["development sprint"] = True
                elif "✅" in block.get("content", "") and "qa and deployment" in content:
                    roadmap_todos["qa and deployment"] = True
    
        missing_todos = [k for k, v in roadmap_todos.items() if not v]
        if missing_todos:
            errors.append(f"[X] Missing Implementation Roadmap todos: {', '.join(missing_todos)}")
        else:
            checks_passed.append(f"[C] has Implementation Roadmap todos: {', '.join(missing_todos)}")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: Comprehensive PRD Surgical Modifications
# =============================================================================
def _validate_agent_prd_surgical_modifications(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Task: On the 'Comprehensive Product Requirements Document' page, perform surgical content
    modifications. Locate the 'User Stories - Part 2' heading_3 (block-47-28) and insert a new
    warning section immediately BEFORE it. Add a callout block with red_background and '⚠️' icon
    containing 'Critical: User stories in this section require stakeholder approval before
    implementation'. Then find all paragraph blocks that start with 'Detailed description' and
    add a to-do block immediately AFTER each one with text '✅ Technical feasibility confirmed'.
    These todos should all be unchecked. Next, navigate to the 'Technical Requirements' section
    and add a new subsection immediately after the heading: add heading_3 'Performance Requirements',
    followed by a numbered list with exactly: '1. Page load time < 3 seconds',
    '2. API response time < 200ms', '3. 99.9% uptime SLA', '4. Support 10,000 concurrent users'.
    Finally, at the very beginning of the page (after the main title but before 'Overview'),
    insert a callout with gray_background and '📋' icon containing
    'Last technical review: [today's date] - Next review scheduled in 30 days'.

    Validates:
    1. Comprehensive PRD page exists
    2. Gray callout with 📋 icon at top with review date (any date format accepted)
    3. Red warning callout with ⚠️ icon before 'User Stories - Part 2' heading
    4. Todo blocks with '✅ Technical feasibility confirmed' after Detailed description paragraphs
    5. Heading3 'Performance Requirements' under Technical Requirements section
    6. Numbered list with 4 performance requirement items
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Find 'Comprehensive Product Requirements Document' page using direct query
    try:
        prd_page = _find_page_by_title_direct(final_state_backend, "Comprehensive Product Requirements Document")
        if not prd_page:
            errors.append("[X] Page 'Comprehensive Product Requirements Document' not found")
        else:
            checks_passed.append("[C] Page 'Comprehensive Product Requirements Document' found")
    
        page_id = prd_page.get("_id")
        if not page_id:
            errors.append("[X] Comprehensive Product Requirements Document page has no _id")
        else:
            checks_passed.append("[C] Comprehensive Product Requirements Document page has _id")
    
        # Get blocks for this page using direct query
        blocks = _get_blocks_for_page_direct(final_state_backend, page_id)
        blocks_sorted = sorted(blocks, key=lambda b: b.get("order", 0))
    
        if not blocks_sorted:
            errors.append("[X] Comprehensive Product Requirements Document page has no content blocks")
        else:
            checks_passed.append("[C] Comprehensive Product Requirements Document page has content blocks")
    
        # 2. Find gray callout with 📋 icon at top (near beginning)
        gray_callout_at_top = False
        for idx, block in enumerate(blocks_sorted[:15]):  # Check first 15 blocks
            if block.get("type") == "callout":
                props = block.get("properties", {})
                bg_color = props.get("backgroundColor", "").lower()
                icon = props.get("icon", "")
                content = block.get("content", "")
                content_lower = content.lower()
            
                # Check for gray/grey background (accept both spellings and default)
                is_gray = "gray" in bg_color or "grey" in bg_color or bg_color in ["", "default"]
            
                # Check for 📋 icon in properties or content
                has_icon = "📋" in icon or "📋" in content
            
                # Check for review-related content
                has_review_content = ("technical review" in content_lower or 
                                      "review" in content_lower or 
                                      ("last" in content_lower and "next" in content_lower))
            
                if is_gray and has_icon and has_review_content:
                    gray_callout_at_top = True
                    break
    
        if not gray_callout_at_top:
            errors.append("[X] Gray callout with 📋 icon containing technical review date not found at top of page")
        else:
            checks_passed.append("[C] Gray callout with 📋 icon containing technical review date found at top of page")
    
        # 3. Find 'User Stories - Part 2' heading and check for red callout before it
        user_stories_part2_idx = -1
        for idx, block in enumerate(blocks_sorted):
            if block.get("type") == "heading3":
                content = block.get("content", "").lower()
                if "user stories - part 2" in content or "user stories part 2" in content:
                    user_stories_part2_idx = idx
                    break
    
        if user_stories_part2_idx == -1:
            errors.append("[X] Heading3 'User Stories - Part 2' not found")
        else:
            checks_passed.append("[C] Heading3 'User Stories - Part 2' found")
    
        # Check for red callout before User Stories Part 2
        red_callout_before_us2 = False
        for idx in range(max(0, user_stories_part2_idx - 5), user_stories_part2_idx):
            block = blocks_sorted[idx]
            if block.get("type") == "callout":
                props = block.get("properties", {})
                bg_color = props.get("backgroundColor", "").lower()
                icon = props.get("icon", "")
                content = block.get("content", "").lower()
            
                if "red" in bg_color and "⚠️" in icon:
                    if "stakeholder approval" in content or "critical" in content:
                        red_callout_before_us2 = True
                        break
    
        if not red_callout_before_us2:
            errors.append("[X] Red callout with ⚠️ icon containing stakeholder approval text not found before 'User Stories - Part 2'")
        else:
            checks_passed.append("[C] Red callout with ⚠️ icon containing stakeholder approval text found before 'User Stories - Part 2'")
    
        # 4. Check for todo blocks with '✅ Technical feasibility confirmed' after Detailed description paragraphs
        # Count paragraphs that start with "Detailed description"
        detailed_desc_count = 0
        for block in blocks_sorted:
            if block.get("type") == "paragraph":
                content = block.get("content", "").lower()
                if content.startswith("detailed description"):
                    detailed_desc_count += 1
    
        # Count todos with technical feasibility text
        tech_feasibility_todos = 0
        for block in blocks_sorted:
            if block.get("type") == "todo":
                content = block.get("content", "")
                if "✅" in content and "technical feasibility confirmed" in content.lower():
                    tech_feasibility_todos += 1
    
        # Should have at least some todos (matching Detailed description paragraphs)
        if tech_feasibility_todos < 1:
            errors.append("[X] No todo blocks with '✅ Technical feasibility confirmed' found after 'Detailed description' paragraphs")
        else:
            checks_passed.append("[C] todo blocks with '✅ Technical feasibility confirmed' found after 'Detailed description' paragraphs")
    
        # 5. Find heading3 'Performance Requirements'
        perf_req_heading_found = False
        for block in blocks_sorted:
            if block.get("type") == "heading3":
                content = block.get("content", "").lower()
                if "performance requirements" in content:
                    perf_req_heading_found = True
                    break
    
        if not perf_req_heading_found:
            errors.append("[X] Heading3 'Performance Requirements' not found under Technical Requirements")
        else:
            checks_passed.append("[C] Heading3 'Performance Requirements' found under Technical Requirements")
    
        # 6. Check for numbered list with 4 performance items
        perf_items = {
            "page load time": False,
            "api response time": False,
            "uptime sla": False,
            "concurrent users": False
        }
    
        for block in blocks_sorted:
            if block.get("type") == "numberedList":
                content = block.get("content", "").lower()
                if "page load" in content and "3 second" in content:
                    perf_items["page load time"] = True
                elif "api response" in content and "200ms" in content:
                    perf_items["api response time"] = True
                elif "99.9" in content and "uptime" in content:
                    perf_items["uptime sla"] = True
                elif "10,000" in content or "10000" in content:
                    perf_items["concurrent users"] = True
    
        missing_perf_items = [k for k, v in perf_items.items() if not v]
        if missing_perf_items:
            errors.append(f"[X] Missing Performance Requirements items: {', '.join(missing_perf_items)}")
        else:
            checks_passed.append(f"[C] has Performance Requirements items: {', '.join(missing_perf_items)}")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: Comprehensive PRD Technical Specifications
# =============================================================================
def _validate_agent_prd_technical_specifications_2(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Task: On the 'Comprehensive Product Requirements Document' page, add a new 'Technical
    Specifications' section precisely between the last 'Overview - Part 3' subsection (after
    its bullet points) and before the next major section. Structure it with: heading2
    '🔧 Technical Specifications', then heading3 '⚡ Performance Requirements' with a numbered
    list: '1. Page load time < 2 seconds', '2. API response time < 200ms', '3. 99.9% uptime SLA'.
    Add heading3 '🔒 Security Requirements' with callout (red_background, icon '🛡️', text
    'All data must be encrypted at rest and in transit'). Then heading3 '📱 Platform Support'
    with a bulleted list exactly matching the format of existing bullet points in Overview
    sections but with content: '• Web: Chrome 90+, Safari 14+, Firefox 88+',
    '• Mobile: iOS 14+, Android 10+', '• API: REST and GraphQL endpoints'.

    Validates:
    1. Comprehensive PRD page exists
    2. Heading2 '🔧 Technical Specifications' exists after Overview Part 3
    3. Heading3 '⚡ Performance Requirements' with 3 numbered list items
    4. Heading3 '🔒 Security Requirements' with red callout and 🛡️ icon
    5. Heading3 '📱 Platform Support' with bulleted list
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Find 'Comprehensive Product Requirements Document' page using direct query
    try:
        prd_page = _find_page_by_title_direct(final_state_backend, "Comprehensive Product Requirements Document")
        if not prd_page:
            errors.append("[X] Page 'Comprehensive Product Requirements Document' not found")
        else:
            checks_passed.append("[C] Page 'Comprehensive Product Requirements Document' found")
    
        page_id = prd_page.get("_id")
        if not page_id:
            errors.append("[X] Comprehensive Product Requirements Document page has no _id")
        else:
            checks_passed.append("[C] Comprehensive Product Requirements Document page has _id")
    
        # Get blocks for this page using direct query
        blocks = _get_blocks_for_page_direct(final_state_backend, page_id)
        blocks_sorted = sorted(blocks, key=lambda b: b.get("order", 0))
    
        if not blocks_sorted:
            errors.append("[X] Comprehensive Product Requirements Document page has no content blocks")
        else:
            checks_passed.append("[C] Comprehensive Product Requirements Document page has content blocks")
    
        # 2. Find heading2 '🔧 Technical Specifications'
        tech_specs_heading_found = False
        tech_specs_idx = -1
        for idx, block in enumerate(blocks_sorted):
            if block.get("type") == "heading2":
                content = block.get("content", "")
                if "🔧" in content and "technical specifications" in content.lower():
                    tech_specs_heading_found = True
                    tech_specs_idx = idx
                    break
    
        if not tech_specs_heading_found:
            errors.append("[X] Heading2 '🔧 Technical Specifications' not found")
        else:
            checks_passed.append("[C] Heading2 '🔧 Technical Specifications' found")
    
        # 3. Find heading3 '⚡ Performance Requirements'
        perf_req_heading_found = False
        for block in blocks_sorted:
            if block.get("type") == "heading3":
                content = block.get("content", "")
                if "⚡" in content and "performance requirements" in content.lower():
                    perf_req_heading_found = True
                    break
    
        if not perf_req_heading_found:
            errors.append("[X] Heading3 '⚡ Performance Requirements' not found")
        else:
            checks_passed.append("[C] Heading3 '⚡ Performance Requirements' found")
    
        # Check for numbered list with performance items
        perf_items = {
            "page load": False,
            "api response": False,
            "uptime": False
        }
    
        for block in blocks_sorted:
            if block.get("type") == "numberedList":
                content = block.get("content", "").lower()
                if "page load" in content and ("2 second" in content or "< 2" in content):
                    perf_items["page load"] = True
                elif "api response" in content and "200ms" in content:
                    perf_items["api response"] = True
                elif "99.9" in content and "uptime" in content:
                    perf_items["uptime"] = True
    
        missing_perf_items = [k for k, v in perf_items.items() if not v]
        if missing_perf_items:
            errors.append(f"[X] Missing Performance Requirements items: {', '.join(missing_perf_items)}")
        else:
            checks_passed.append(f"[C] has Performance Requirements items: {', '.join(missing_perf_items)}")
    
        # 4. Find heading3 '🔒 Security Requirements'
        security_heading_found = False
        for block in blocks_sorted:
            if block.get("type") == "heading3":
                content = block.get("content", "")
                if "🔒" in content and "security requirements" in content.lower():
                    security_heading_found = True
                    break
    
        if not security_heading_found:
            errors.append("[X] Heading3 '🔒 Security Requirements' not found")
        else:
            checks_passed.append("[C] Heading3 '🔒 Security Requirements' found")
    
        # Check for red callout with 🛡️ icon
        security_callout_found = False
        for block in blocks_sorted:
            if block.get("type") == "callout":
                props = block.get("properties", {})
                bg_color = props.get("backgroundColor", "").lower()
                icon = props.get("icon", "")
                content = block.get("content", "").lower()
            
                if "red" in bg_color and "🛡️" in icon:
                    if "encrypted" in content or "data" in content:
                        security_callout_found = True
                        break
    
        if not security_callout_found:
            errors.append("[X] Red callout with 🛡️ icon containing encryption text not found")
        else:
            checks_passed.append("[C] Red callout with 🛡️ icon containing encryption text found")
    
        # 5. Find heading3 '📱 Platform Support'
        platform_heading_found = False
        for block in blocks_sorted:
            if block.get("type") == "heading3":
                content = block.get("content", "")
                if "📱" in content and "platform support" in content.lower():
                    platform_heading_found = True
                    break
    
        if not platform_heading_found:
            errors.append("[X] Heading3 '📱 Platform Support' not found")
        else:
            checks_passed.append("[C] Heading3 '📱 Platform Support' found")
    
        # Check for bulleted list with platform items
        platform_items = {
            "web": False,
            "mobile": False,
            "api": False
        }
    
        for block in blocks_sorted:
            if block.get("type") == "bulletedList":
                content = block.get("content", "").lower()
                if "web" in content and ("chrome" in content or "safari" in content or "firefox" in content):
                    platform_items["web"] = True
                elif "mobile" in content and ("ios" in content or "android" in content):
                    platform_items["mobile"] = True
                elif "api" in content and ("rest" in content or "graphql" in content):
                    platform_items["api"] = True
    
        missing_platform_items = [k for k, v in platform_items.items() if not v]
        if missing_platform_items:
            errors.append(f"[X] Missing Platform Support items: {', '.join(missing_platform_items)}")
        else:
            checks_passed.append(f"[C] has Platform Support items: {', '.join(missing_platform_items)}")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: Project Documentation Table of Contents
# =============================================================================
def _validate_agent_project_documentation_toc(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Task: In the 'Project Documentation' page, create a comprehensive table of contents. First,
    fetch and analyze all child pages recursively (Architecture > Frontend Architecture > Component
    Library, etc.). Add a heading2 '📚 Documentation Structure' at the very beginning after the
    main title. For each top-level child page, create a heading3 with format '📁 [Page Title]'.
    Under each heading3, add a numbered list of all sub-pages with their icons. For pages with
    further children, indent using bulleted lists. After the complete hierarchy, add a divider
    and a paragraph: 'Total documentation pages: [COUNT] across [LEVELS] levels of hierarchy'.
    Finally, add a callout with yellow_background, icon '💡': 'Click any page title to navigate
    directly to that section'.

    Validates:
    1. Project Documentation page exists
    2. Heading2 '📚 Documentation Structure' at beginning
    3. Heading3 sections for top-level child pages with 📁 prefix
    4. Numbered/bulleted lists for sub-pages showing hierarchy
    5. Divider after complete hierarchy
    6. Paragraph with total page count and hierarchy levels
    7. Yellow callout with 💡 icon
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Find 'Project Documentation' page using direct query
    try:
        project_doc_page = _find_page_by_title_direct(final_state_backend, "Project Documentation")
        if not project_doc_page:
            errors.append("[X] Page 'Project Documentation' not found")
        else:
            checks_passed.append("[C] Page 'Project Documentation' found")
    
        page_id = project_doc_page.get("_id")
        if not page_id:
            errors.append("[X] Project Documentation page has no _id")
        else:
            checks_passed.append("[C] Project Documentation page has _id")
    
        # Get blocks for this page using direct query
        blocks = _get_blocks_for_page_direct(final_state_backend, page_id)
        blocks_sorted = sorted(blocks, key=lambda b: b.get("order", 0))
    
        if not blocks_sorted:
            errors.append("[X] Project Documentation page has no content blocks")
        else:
            checks_passed.append("[C] Project Documentation page has content blocks")
    
        # 2. Find heading2 '📚 Documentation Structure' at beginning
        doc_structure_heading_found = False
        doc_structure_idx = -1
        for idx, block in enumerate(blocks_sorted):
            if block.get("type") == "heading2":
                content = block.get("content", "")
                if "📚" in content and "documentation structure" in content.lower():
                    doc_structure_heading_found = True
                    doc_structure_idx = idx
                    break
    
        if not doc_structure_heading_found:
            errors.append("[X] Heading2 '📚 Documentation Structure' not found")
        else:
            checks_passed.append("[C] Heading2 '📚 Documentation Structure' found")
    
        # 3. Find heading3 sections with 📁 prefix for top-level children
        folder_headings = []
        for block in blocks_sorted:
            if block.get("type") == "heading3":
                content = block.get("content", "")
                if "📁" in content:
                    folder_headings.append(content)
    
        if len(folder_headings) < 1:
            errors.append("[X] No heading3 sections with '📁' prefix found for child pages")
        else:
            checks_passed.append("[C] heading3 sections with '📁' prefix found for child pages")
    
        # 4. Check for numbered or bulleted lists
        has_numbered_list = False
        has_bulleted_list = False
    
        for block in blocks_sorted:
            if block.get("type") == "numberedList":
                has_numbered_list = True
            elif block.get("type") == "bulletedList":
                has_bulleted_list = True
    
        if not (has_numbered_list or has_bulleted_list):
            errors.append("[X] No numbered or bulleted lists found for sub-page listings")
        else:
            checks_passed.append("[C] numbered or bulleted lists found for sub-page listings")
    
        # 5. Find divider
        divider_found = False
        divider_idx = -1
        for idx, block in enumerate(blocks_sorted):
            if block.get("type") == "divider":
                divider_found = True
                divider_idx = idx
                break
    
        if not divider_found:
            errors.append("[X] Divider not found after hierarchy")
        else:
            checks_passed.append("[C] Divider found after hierarchy")
    
        # 6. Find paragraph with page count and hierarchy levels
        count_paragraph_found = False
        for block in blocks_sorted:
            if block.get("type") == "paragraph":
                content = block.get("content", "").lower()
                if "total documentation pages" in content or ("total" in content and "pages" in content):
                    if "level" in content or "hierarchy" in content:
                        count_paragraph_found = True
                        break
    
        if not count_paragraph_found:
            errors.append("[X] Paragraph with total page count and hierarchy levels not found")
        else:
            checks_passed.append("[C] Paragraph with total page count and hierarchy levels found")
    
        # 7. Find yellow callout with 💡 icon
        yellow_callout_found = False
        for block in blocks_sorted:
            if block.get("type") == "callout":
                props = block.get("properties", {})
                bg_color = props.get("backgroundColor", "").lower()
                icon = props.get("icon", "")
                content = block.get("content", "").lower()
            
                if "yellow" in bg_color and "💡" in icon:
                    if "click" in content or "navigate" in content:
                        yellow_callout_found = True
                        break
    
        if not yellow_callout_found:
            errors.append("[X] Yellow callout with 💡 icon and navigation hint not found")
        else:
            checks_passed.append("[C] Yellow callout with 💡 icon and navigation hint found")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_agent_reorganize_onboarding_guide_structure(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Task: Reorganize the 'Onboarding Guide' page by swapping sections and adding new content.
    
    Prompt: "On the 'Onboarding Guide' page, reorganize the content structure. First, swap the positions 
    of the 'First Day Tasks' section (including all its numbered list items) with the 'First Week Goals' 
    section (including all its numbered list items). After swapping, insert a divider block between these 
    two sections. Then add a new heading_2 block with text '🎯 30-Day Milestones' at the very end of the 
    page, followed by a callout block with green_background color, icon '📌', and text 'Checkpoint: 
    Schedule your 30-day review with your manager'. Finally, add three unchecked to-do blocks with exact 
    texts: 'Complete initial project assignment', 'Present learnings to the team', 'Submit feedback on 
    onboarding process'."
    
    Validates:
    1. Find 'Onboarding Guide' page exists
    2. 'First Week Goals' heading2 appears BEFORE 'First Day Tasks' heading2 (by order)
    3. Both sections retain their numbered list items
    4. Divider block exists between 'First Week Goals' section and 'First Day Tasks' heading
    5. heading2 '🎯 30-Day Milestones' exists at end of page
    6. Callout with green_background, '📌' icon, and exact text
    7. Three unchecked todo blocks with exact texts
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Find 'Onboarding Guide' page using direct query
    try:
        onboarding_page = _find_page_by_title_direct(backend, "Onboarding Guide")
        if not onboarding_page:
            errors.append("[X] Page 'Onboarding Guide' not found")
        else:
            checks_passed.append("[C] Page 'Onboarding Guide' found")
    
        page_id = onboarding_page.get("_id")
        if not page_id:
            errors.append("[X] Onboarding Guide page has no _id")
        else:
            checks_passed.append("[C] Onboarding Guide page has _id")
    
        # Get all blocks for the page using direct query
        blocks = _get_blocks_for_page_direct(backend, page_id)
        if not blocks:
            errors.append("[X] Page 'Onboarding Guide' has no content blocks")
        else:
            checks_passed.append("[C] Page 'Onboarding Guide' has content blocks")
    
        blocks.sort(key=lambda b: b.get("order", 0))
    
        # 2. Find 'First Day Tasks' and 'First Week Goals' headings
        first_day_idx = None
        first_week_idx = None
        first_day_order = None
        first_week_order = None
    
        for i, block in enumerate(blocks):
            if block.get("type") == "heading2":
                content_lower = block.get("content", "").lower()
                if "first day tasks" in content_lower:
                    first_day_idx = i
                    first_day_order = block.get("order", 0)
                elif "first week goals" in content_lower:
                    first_week_idx = i
                    first_week_order = block.get("order", 0)
    
        if first_day_idx is None:
            errors.append("[X] Heading 'First Day Tasks' not found")
        else:
            checks_passed.append("[C] Heading 'First Day Tasks' found")
    
        if first_week_idx is None:
            errors.append("[X] Heading 'First Week Goals' not found")
        else:
            checks_passed.append("[C] Heading 'First Week Goals' found")
    
        # Verify sections are swapped: First Week Goals should come BEFORE First Day Tasks
        if first_week_order >= first_day_order:
            errors.append(f"[X] Sections not swapped: 'First Week Goals' (order {first_week_order}) should come BEFORE 'First Day Tasks' (order {first_day_order})")
        else:
            checks_passed.append(f"[C] Sections swapped: 'First Week Goals' (order {first_week_order}) should come BEFORE 'First Day Tasks' (order {first_day_order})")
    
        # 3. Verify numbered list items exist in each section
        first_week_list_count = 0
        first_day_list_count = 0
    
        # Count numbered items after First Week Goals until we hit First Day Tasks or another heading2
        in_first_week_section = False
        in_first_day_section = False
    
        for block in blocks:
            block_type = block.get("type", "")
            content_lower = block.get("content", "").lower()
        
            if block_type == "heading2":
                if "first week goals" in content_lower:
                    in_first_week_section = True
                    in_first_day_section = False
                elif "first day tasks" in content_lower:
                    in_first_week_section = False
                    in_first_day_section = True
                else:
                    in_first_week_section = False
                    in_first_day_section = False
            elif block_type == "numberedList":
                if in_first_week_section:
                    first_week_list_count += 1
                elif in_first_day_section:
                    first_day_list_count += 1
    
        if first_week_list_count < 3:
            errors.append(f"[X] 'First Week Goals' section should have at least 3 numbered items, found {first_week_list_count}")
        else:
            checks_passed.append(f"[C] 'First Week Goals' section should have at least 3 numbered items, found {first_week_list_count}")
    
        if first_day_list_count < 3:
            errors.append(f"[X] 'First Day Tasks' section should have at least 3 numbered items, found {first_day_list_count}")
        else:
            checks_passed.append(f"[C] 'First Day Tasks' section should have at least 3 numbered items, found {first_day_list_count}")
    
        # 4. Verify divider exists between First Week Goals section and First Day Tasks heading
        divider_found_between = False
        passed_first_week_items = False
    
        for block in blocks:
            block_order = block.get("order", 0)
            block_type = block.get("type", "")
            content_lower = block.get("content", "").lower()
        
            # After First Week Goals section items, before First Day Tasks
            if block_order > first_week_order and block_order < first_day_order:
                if block_type == "divider":
                    divider_found_between = True
                    break
    
        if not divider_found_between:
            errors.append("[X] Divider not found between 'First Week Goals' section and 'First Day Tasks' heading")
        else:
            checks_passed.append("[C] Divider found between 'First Week Goals' section and 'First Day Tasks' heading")
    
        # 5. Find heading2 '🎯 30-Day Milestones' at end of page
        milestones_heading_idx = None
        milestones_heading_order = None
    
        for i, block in enumerate(blocks):
            if block.get("type") == "heading2":
                content = block.get("content", "")
                if "30-day milestones" in content.lower() or "30-Day Milestones" in content:
                    milestones_heading_idx = i
                    milestones_heading_order = block.get("order", 0)
    
        if milestones_heading_idx is None:
            errors.append("[X] Heading '🎯 30-Day Milestones' not found")
        else:
            checks_passed.append("[C] Heading '🎯 30-Day Milestones' found")
    
        # Verify it's at the end (after First Day Tasks section)
        if milestones_heading_order <= first_day_order:
            errors.append(f"[X] '🎯 30-Day Milestones' heading should be at the END of page (after 'First Day Tasks')")
        else:
            checks_passed.append(f"[C] '🎯 30-Day Milestones' heading should be at the END of page (after 'First Day Tasks')")
    
        # 6. Verify callout with green_background, '📌' icon, and exact text
        callout_found = False
        expected_callout_text = "Checkpoint: Schedule your 30-day review with your manager"
    
        for block in blocks:
            if block.get("type") == "callout":
                block_order = block.get("order", 0)
                # Must be after milestones heading
                if block_order > milestones_heading_order:
                    props = block.get("properties", {})
                    bg_color = props.get("backgroundColor", "").lower()
                    icon = props.get("icon", "")
                    content = block.get("content", "")
                
                    if "green" in bg_color and "📌" in icon:
                        if expected_callout_text.lower() in content.lower():
                            callout_found = True
                            break
    
        if not callout_found:
            errors.append(f"[X] Callout with green_background, '📌' icon, and text '{expected_callout_text}' not found after '🎯 30-Day Milestones' heading")
        else:
            checks_passed.append(f"[C] Callout with green_background, '📌' icon, and text '{expected_callout_text}' found after '🎯 30-Day Milestones' heading")
    
        # 7. Verify three unchecked todo blocks with exact texts
        expected_todos = [
            "complete initial project assignment",
            "present learnings to the team",
            "submit feedback on onboarding process"
        ]
        found_todos = []
    
        for block in blocks:
            if block.get("type") == "todo":
                block_order = block.get("order", 0)
                # Must be after milestones heading
                if block_order > milestones_heading_order:
                    props = block.get("properties", {})
                    checked = props.get("checked", False)
                    content = block.get("content", "").lower()
                
                    for expected in expected_todos:
                        if expected in content and expected not in found_todos:
                            if checked:
                                errors.append(f"[X] Todo '{expected}' should be unchecked but is checked")
                            else:
                                checks_passed.append(f"[C] Todo '{expected}' should be unchecked but is checked")
                            found_todos.append(expected)
    
        if len(found_todos) < 3:
            missing = [t for t in expected_todos if t not in found_todos]
            errors.append(f"[X] Missing unchecked todo blocks: {', '.join(missing)}")
        else:
            checks_passed.append(f"[C] has unchecked todo blocks")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_agent_add_bug_analysis_dashboard(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Task: Add a comprehensive bug analysis section to the 'Bug Tracker' page.
    
    Prompt: "Find the 'Bug Tracker' page and add a comprehensive bug analysis section. At the end of the 
    page, add heading_2 '🐛 Bug Analysis Dashboard'. Below it, add heading_3 '📊 Bug Categories' followed 
    by these exact callout blocks in order: 1) Red background, icon '🔴', text 'Critical: Database 
    connection failures (3 reports)', 2) Orange background, icon '🟠', text 'High: Performance degradation 
    on search (5 reports)', 3) Yellow background, icon '🟡', text 'Medium: UI rendering glitches (8 reports)', 
    4) Green background, icon '🟢', text 'Low: Typos and text improvements (12 reports)'. Then add heading_3 
    '📈 Trend Analysis' with a paragraph 'Total bugs this sprint: 28 | Resolved: 15 | Resolution rate: 53.6%'."
    
    Validates:
    1. Find 'Bug Tracker' page exists
    2. heading2 '🐛 Bug Analysis Dashboard' exists at end of page
    3. heading3 '📊 Bug Categories' exists after dashboard heading
    4. Four callouts in correct order with correct colors, icons, and texts
    5. heading3 '📈 Trend Analysis' exists after callouts
    6. Paragraph with statistics exists
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Find 'Bug Tracker' page using direct query
    try:
        bug_tracker_page = _find_page_by_title_direct(backend, "Bug Tracker")
        if not bug_tracker_page:
            errors.append("[X] Page 'Bug Tracker' not found")
        else:
            checks_passed.append("[C] Page 'Bug Tracker' found")
    
        page_id = bug_tracker_page.get("_id")
        if not page_id:
            errors.append("[X] Bug Tracker page has no _id")
        else:
            checks_passed.append("[C] Bug Tracker page has _id")
    
        # Get all blocks for the page using direct query
        blocks = _get_blocks_for_page_direct(backend, page_id)
        if not blocks:
            errors.append("[X] Page 'Bug Tracker' has no content blocks")
        else:
            checks_passed.append("[C] Page 'Bug Tracker' has content blocks")
    
        blocks.sort(key=lambda b: b.get("order", 0))
    
        # 2. Find heading2 '🐛 Bug Analysis Dashboard'
        dashboard_heading_idx = None
        dashboard_heading_order = None
    
        for i, block in enumerate(blocks):
            if block.get("type") == "heading2":
                content = block.get("content", "")
                if "bug analysis dashboard" in content.lower():
                    dashboard_heading_idx = i
                    dashboard_heading_order = block.get("order", 0)
                    break
    
        if dashboard_heading_idx is None:
            errors.append("[X] Heading '🐛 Bug Analysis Dashboard' not found")
        else:
            checks_passed.append("[C] Heading '🐛 Bug Analysis Dashboard' found")
    
        # Verify it's at the end (find original content order)
        original_sections = ["critical bugs", "medium priority", "low priority"]
        max_original_order = 0
        for block in blocks:
            content_lower = block.get("content", "").lower()
            for section in original_sections:
                if section in content_lower:
                    max_original_order = max(max_original_order, block.get("order", 0))
    
        if dashboard_heading_order <= max_original_order:
            errors.append("[X] Bug Analysis Dashboard heading should be at the END of the page (after original content)")
        else:
            checks_passed.append("[C] Bug Analysis Dashboard heading should be at the END of the page (after original content)")
    
        # 3. Find heading3 '📊 Bug Categories'
        categories_heading_order = None
    
        for block in blocks:
            if block.get("type") == "heading3":
                content = block.get("content", "")
                if "bug categories" in content.lower():
                    categories_heading_order = block.get("order", 0)
                    break
    
        if categories_heading_order is None:
            errors.append("[X] Heading '📊 Bug Categories' not found")
        else:
            checks_passed.append("[C] Heading '📊 Bug Categories' found")
    
        if categories_heading_order <= dashboard_heading_order:
            errors.append("[X] Bug Categories heading should appear AFTER Bug Analysis Dashboard heading")
        else:
            checks_passed.append("[C] Bug Categories heading should appear AFTER Bug Analysis Dashboard heading")
    
        # 4. Find and validate four callouts in correct order
        expected_callouts = [
            {"bg": "red", "icon": "🔴", "text": "Critical: Database connection failures (3 reports)"},
            {"bg": "orange", "icon": "🟠", "text": "High: Performance degradation on search (5 reports)"},
            {"bg": "yellow", "icon": "🟡", "text": "Medium: UI rendering glitches (8 reports)"},
            {"bg": "green", "icon": "🟢", "text": "Low: Typos and text improvements (12 reports)"},
        ]
    
        # Collect callouts after categories heading
        callouts_found = []
        for block in blocks:
            if block.get("type") == "callout":
                block_order = block.get("order", 0)
                if block_order > categories_heading_order:
                    props = block.get("properties", {})
                    callouts_found.append({
                        "order": block_order,
                        "bg": props.get("backgroundColor", "").lower(),
                        "icon": props.get("icon", ""),
                        "text": block.get("content", "")
                    })
    
        # Sort by order
        callouts_found.sort(key=lambda x: x["order"])
    
        if len(callouts_found) < 4:
            errors.append(f"[X] Expected 4 callouts in Bug Categories section, found {len(callouts_found)}")
        else:
            checks_passed.append(f"[C] Found 4 callouts in Bug Categories section as expected")
    
        # Validate each callout in order
        for i, expected in enumerate(expected_callouts):
            if i >= len(callouts_found):
                errors.append(f"[X] Missing callout {i+1}: {expected['text']}")
            else:
                checks_passed.append(f"[C] has callout {i+1}: {expected['text']}")
        
            found = callouts_found[i]
        
            # Check background color
            if expected["bg"] not in found["bg"]:
                errors.append(f"[X] Callout {i+1} should have {expected['bg']}_background, found '{found['bg']}'")
            else:
                checks_passed.append(f"[C] Callout {i+1} should have {expected['bg']}_background, found '{found['bg']}'")
        
            # Check icon
            if expected["icon"] not in found["icon"]:
                errors.append(f"[X] Callout {i+1} should have icon '{expected['icon']}', found '{found['icon']}'")
            else:
                checks_passed.append(f"[C] Callout {i+1} should have icon '{expected['icon']}', found '{found['icon']}'")
        
            # Check text (flexible matching)
            if expected["text"].lower() not in found["text"].lower():
                errors.append(f"[X] Callout {i+1} text mismatch. Expected: '{expected['text']}', Found: '{found['text']}'")
            else:
                checks_passed.append(f"[C] Callout {i+1} text mismatch. Expected: '{expected['text']}', Found: '{found['text']}'")
    
        # 5. Find heading3 '📈 Trend Analysis'
        trend_heading_order = None
    
        for block in blocks:
            if block.get("type") == "heading3":
                content = block.get("content", "")
                if "trend analysis" in content.lower():
                    trend_heading_order = block.get("order", 0)
                    break
    
        if trend_heading_order is None:
            errors.append("[X] Heading '📈 Trend Analysis' not found")
        else:
            checks_passed.append("[C] Heading '📈 Trend Analysis' found")
    
        # Verify it's after the callouts
        last_callout_order = callouts_found[3]["order"] if len(callouts_found) >= 4 else 0
        if trend_heading_order <= last_callout_order:
            errors.append("[X] Trend Analysis heading should appear AFTER the callouts")
        else:
            checks_passed.append("[C] Trend Analysis heading should appear AFTER the callouts")
    
        # 6. Find paragraph with statistics
        stats_found = False
        expected_stats = "Total bugs this sprint: 28 | Resolved: 15 | Resolution rate: 53.6%"
    
        for block in blocks:
            if block.get("type") == "paragraph":
                block_order = block.get("order", 0)
                if block_order > trend_heading_order:
                    content = block.get("content", "")
                    content_lower = content.lower()
                    # Check for key elements
                    if ("total" in content_lower and "28" in content) or \
                       ("resolved" in content_lower and "15" in content) or \
                       ("53.6" in content or "53.6%" in content):
                        stats_found = True
                        break
    
        if not stats_found:
            errors.append(f"[X] Paragraph with statistics '{expected_stats}' not found after Trend Analysis heading")
        else:
            checks_passed.append(f"[C] Paragraph with statistics '{expected_stats}' found after Trend Analysis heading")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_agent_duplicate_standup_section_with_progress(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Task: Duplicate and modify sections in 'Weekly Standup Template' page.
    
    Prompt: "On the 'Weekly Standup Template' page: First, duplicate the entire 'What I did this week' 
    section (heading and all todos) and place it immediately after the 'Blockers' section. Change the 
    duplicated heading to 'What I accomplished last week'. Then, between the original 'What I did this week' 
    and 'What I plan to do next week' sections, insert a new heading2 '📊 Week-over-week Progress' with a 
    callout below it having yellow_background and '📈' icon containing: 'Track your velocity: This week [X] 
    tasks vs Last week [Y] tasks' where X and Y are counts of todos in respective sections. Mark all todos 
    in the duplicated 'accomplished' section as checked."
    
    Validates:
    1. Find 'Weekly Standup Template' page exists
    2. heading2 'What I accomplished last week' exists
    3. 'What I accomplished last week' section appears AFTER 'Blockers' section
    4. 'What I accomplished last week' section has todos (duplicated)
    5. ALL todos under 'What I accomplished last week' are checked
    6. heading2 '📊 Week-over-week Progress' exists between 'What I did this week' and 'What I plan to do next week'
    7. Yellow callout with '📈' icon and velocity text exists
    8. Original 'What I did this week' section preserved
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Find 'Weekly Standup Template' page using direct query
    try:
        standup_page = _find_page_by_title_direct(backend, "Weekly Standup Template")
        if not standup_page:
            errors.append("[X] Page 'Weekly Standup Template' not found")
        else:
            checks_passed.append("[C] Page 'Weekly Standup Template' found")
    
        page_id = standup_page.get("_id")
        if not page_id:
            errors.append("[X] Weekly Standup Template page has no _id")
        else:
            checks_passed.append("[C] Weekly Standup Template page has _id")
    
        # Get all blocks for the page using direct query
        blocks = _get_blocks_for_page_direct(backend, page_id)
        if not blocks:
            errors.append("[X] Page 'Weekly Standup Template' has no content blocks")
        else:
            checks_passed.append("[C] Page 'Weekly Standup Template' has content blocks")
    
        blocks.sort(key=lambda b: b.get("order", 0))
    
        # Find key section headings
        what_i_did_order = None
        what_i_plan_order = None
        blockers_order = None
        accomplished_order = None
        progress_order = None
    
        for block in blocks:
            if block.get("type") == "heading2":
                content_lower = block.get("content", "").lower()
                order = block.get("order", 0)
            
                if "what i did this week" in content_lower:
                    what_i_did_order = order
                elif "what i plan to do next week" in content_lower:
                    what_i_plan_order = order
                elif "blockers" in content_lower:
                    blockers_order = order
                elif "what i accomplished last week" in content_lower:
                    accomplished_order = order
                elif "week-over-week progress" in content_lower or "week over week progress" in content_lower:
                    progress_order = order
    
        # 2. Verify 'What I accomplished last week' heading exists
        if accomplished_order is None:
            errors.append("[X] Heading 'What I accomplished last week' not found")
        else:
            checks_passed.append("[C] Heading 'What I accomplished last week' found")
    
        # 3. Verify 'What I accomplished last week' appears AFTER 'Blockers'
        if blockers_order is None:
            errors.append("[X] Heading 'Blockers' not found")
        else:
            checks_passed.append("[C] Heading 'Blockers' found")
    
        if accomplished_order <= blockers_order:
            errors.append(f"[X] 'What I accomplished last week' (order {accomplished_order}) should appear AFTER 'Blockers' (order {blockers_order})")
        else:
            checks_passed.append(f"[C] 'What I accomplished last week' (order {accomplished_order}) should appear AFTER 'Blockers' (order {blockers_order})")
    
        # 4. Verify 'What I accomplished last week' section has todos
        accomplished_todos = []
        in_accomplished_section = False
    
        for block in blocks:
            block_type = block.get("type", "")
            content_lower = block.get("content", "").lower()
            block_order = block.get("order", 0)
        
            if block_type == "heading2":
                if "what i accomplished last week" in content_lower:
                    in_accomplished_section = True
                elif in_accomplished_section:
                    # Hit another heading, section ended
                    break
            elif block_type == "todo" and in_accomplished_section:
                accomplished_todos.append(block)
    
        if len(accomplished_todos) < 2:
            errors.append(f"[X] 'What I accomplished last week' section should have at least 2 todos (duplicated from original), found {len(accomplished_todos)}")
        else:
            checks_passed.append(f"[C] 'What I accomplished last week' section should have at least 2 todos (duplicated from original), found {len(accomplished_todos)}")
    
        # 5. Verify ALL todos in accomplished section are checked
        for todo in accomplished_todos:
            props = todo.get("properties", {})
            if not props.get("checked", False):
                errors.append(f"[X] Todo '{todo.get('content', '')}' in 'What I accomplished last week' section should be checked")
            else:
                checks_passed.append(f"[C] Todo '{todo.get('content', '')}' in 'What I accomplished last week' section should be checked")
    
        # 6. Verify '📊 Week-over-week Progress' heading exists between 'What I did' and 'What I plan'
        if what_i_did_order is None:
            errors.append("[X] Heading 'What I did this week' not found")
        else:
            checks_passed.append("[C] Heading 'What I did this week' found")
    
        if what_i_plan_order is None:
            errors.append("[X] Heading 'What I plan to do next week' not found")
        else:
            checks_passed.append("[C] Heading 'What I plan to do next week' found")
    
        if progress_order is None:
            errors.append("[X] Heading '📊 Week-over-week Progress' not found")
        else:
            checks_passed.append("[C] Heading '📊 Week-over-week Progress' found")
    
        if not (what_i_did_order < progress_order < what_i_plan_order):
            errors.append(f"[X] '📊 Week-over-week Progress' (order {progress_order}) should be BETWEEN 'What I did this week' (order {what_i_did_order}) and 'What I plan to do next week' (order {what_i_plan_order})")
        else:
            checks_passed.append(f"[C] '📊 Week-over-week Progress' (order {progress_order}) should be BETWEEN 'What I did this week' (order {what_i_did_order}) and 'What I plan to do next week' (order {what_i_plan_order})")
    
        # 7. Verify yellow callout with '📈' icon and velocity text
        velocity_callout_found = False
    
        for block in blocks:
            if block.get("type") == "callout":
                block_order = block.get("order", 0)
                # Must be after progress heading and before 'What I plan'
                if progress_order < block_order < what_i_plan_order:
                    props = block.get("properties", {})
                    bg_color = props.get("backgroundColor", "").lower()
                    icon = props.get("icon", "")
                    content = block.get("content", "").lower()
                
                    if "yellow" in bg_color and "📈" in icon:
                        # Check for velocity-related text
                        if ("velocity" in content or "track" in content) and ("this week" in content or "last week" in content):
                            velocity_callout_found = True
                            break
    
        if not velocity_callout_found:
            errors.append("[X] Callout with yellow_background, '📈' icon, and velocity tracking text not found between Progress heading and 'What I plan' section")
        else:
            checks_passed.append("[C] Callout with yellow_background, '📈' icon, and velocity tracking text found between Progress heading and 'What I plan' section")
    
        # 8. Verify original 'What I did this week' section is preserved (has todos)
        original_todos = []
        in_original_section = False
    
        for block in blocks:
            block_type = block.get("type", "")
            content_lower = block.get("content", "").lower()
            block_order = block.get("order", 0)
        
            if block_type == "heading2":
                if "what i did this week" in content_lower:
                    in_original_section = True
                elif in_original_section:
                    # Hit another heading (like Progress), section ended
                    break
            elif block_type == "todo" and in_original_section:
                original_todos.append(block)
    
        if len(original_todos) < 2:
            errors.append(f"[X] Original 'What I did this week' section should be preserved with todos, found {len(original_todos)}")
        else:
            checks_passed.append(f"[C] Original 'What I did this week' section should be preserved with todos, found {len(original_todos)}")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_agent_add_sprint_metrics_section(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Task: Add Sprint Metrics section to 'Sprint Planning - Jan 15' page.
    
    Prompt: "Navigate to the 'Sprint Planning - Jan 15' page under Meeting Notes. Add a new section 
    immediately AFTER the 'Action Items' heading but at the very end of the page. Create a heading2 
    '📊 Sprint Metrics', followed by a paragraph analyzing the todo items: 'Sprint planning resulted 
    in [X] action items, with [Y] completed ([Z]% completion rate).' Then add a heading3 '🎯 Goal 
    Achievement', followed by a numbered list analyzing the Sprint Goals section - for each numbered 
    item in Sprint Goals, add a corresponding numbered list item showing 'Goal [N]: [Goal text] - 
    Status: [In Progress/Complete based on context]'. Finally, add a callout with blue_background 
    and 📈 icon: 'Next sprint planning scheduled for January 29, 2024'."
    
    Validates:
    1. Find 'Sprint Planning - Jan 15' page exists
    2. heading2 '📊 Sprint Metrics' exists at the END of the page
    3. Paragraph with action item analysis (X items, Y completed, Z% rate)
    4. heading3 '🎯 Goal Achievement' exists
    5. Numbered list with 3 items corresponding to Sprint Goals
    6. Blue callout with '📈' icon and January 29 date
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Find 'Sprint Planning - Jan 15' page using direct query
    try:
        sprint_page = _find_page_by_title_direct(backend, "Sprint Planning - Jan 15")
        if not sprint_page:
            # Try alternate title
            sprint_page = _find_page_by_title_direct(backend, "Sprint Planning")
            if not sprint_page:
                errors.append("[X] Page 'Sprint Planning - Jan 15' not found")
            else:
                checks_passed.append("[C] Page 'Sprint Planning - Jan 15' found")
    
        page_id = sprint_page.get("_id")
        if not page_id:
            errors.append("[X] Sprint Planning page has no _id")
        else:
            checks_passed.append("[C] Sprint Planning page has _id")
    
        # Get all blocks for the page using direct query
        blocks = _get_blocks_for_page_direct(backend, page_id)
        if not blocks:
            errors.append("[X] Page 'Sprint Planning - Jan 15' has no content blocks")
        else:
            checks_passed.append("[C] Page 'Sprint Planning - Jan 15' has content blocks")
    
        blocks.sort(key=lambda b: b.get("order", 0))
    
        # Find key section headings and their orders
        action_items_order = None
        sprint_metrics_order = None
        goal_achievement_order = None
    
        for block in blocks:
            if block.get("type") == "heading2":
                content_lower = block.get("content", "").lower()
                order = block.get("order", 0)
            
                if "action items" in content_lower:
                    action_items_order = order
                elif "sprint metrics" in content_lower:
                    sprint_metrics_order = order
            elif block.get("type") == "heading3":
                content_lower = block.get("content", "").lower()
                order = block.get("order", 0)
            
                if "goal achievement" in content_lower:
                    goal_achievement_order = order
    
        # 2. Verify '📊 Sprint Metrics' heading exists at END
        if sprint_metrics_order is None:
            errors.append("[X] Heading '📊 Sprint Metrics' not found")
        else:
            checks_passed.append("[C] Heading '📊 Sprint Metrics' found")
    
        if action_items_order is None:
            errors.append("[X] Heading 'Action Items' not found")
        else:
            checks_passed.append("[C] Heading 'Action Items' found")
    
        if sprint_metrics_order <= action_items_order:
            errors.append(f"[X] '📊 Sprint Metrics' (order {sprint_metrics_order}) should appear AFTER 'Action Items' (order {action_items_order})")
        else:
            checks_passed.append(f"[C] '📊 Sprint Metrics' (order {sprint_metrics_order}) should appear AFTER 'Action Items' (order {action_items_order})")
    
        # 3. Verify paragraph with action item analysis
        analysis_paragraph_found = False
    
        for block in blocks:
            if block.get("type") == "paragraph":
                block_order = block.get("order", 0)
                if block_order > sprint_metrics_order:
                    content = block.get("content", "").lower()
                    # Check for key elements of the analysis text
                    if ("sprint planning" in content or "action items" in content) and \
                       ("completed" in content or "completion" in content):
                        analysis_paragraph_found = True
                        break
    
        if not analysis_paragraph_found:
            errors.append("[X] Paragraph analyzing action items (with completion count/rate) not found after Sprint Metrics heading")
        else:
            checks_passed.append("[C] Paragraph analyzing action items (with completion count/rate) found after Sprint Metrics heading")
    
        # 4. Verify '🎯 Goal Achievement' heading exists
        if goal_achievement_order is None:
            errors.append("[X] Heading '🎯 Goal Achievement' not found")
        else:
            checks_passed.append("[C] Heading '🎯 Goal Achievement' found")
    
        if goal_achievement_order <= sprint_metrics_order:
            errors.append(f"[X] '🎯 Goal Achievement' (order {goal_achievement_order}) should appear AFTER '📊 Sprint Metrics' (order {sprint_metrics_order})")
        else:
            checks_passed.append(f"[C] '🎯 Goal Achievement' (order {goal_achievement_order}) should appear AFTER '📊 Sprint Metrics' (order {sprint_metrics_order})")
    
        # 5. Verify numbered list with goal items
        # Original Sprint Goals: 1) Complete authentication flow redesign, 2) Implement block drag-and-drop, 3) Add page sharing permissions UI
        expected_goals = [
            "authentication",
            "drag-and-drop",
            "sharing",
        ]
    
        goals_found = 0
        for block in blocks:
            if block.get("type") == "numberedList":
                block_order = block.get("order", 0)
                if block_order > goal_achievement_order:
                    content_lower = block.get("content", "").lower()
                    # Check if it references any of the original goals
                    for goal_keyword in expected_goals:
                        if goal_keyword in content_lower:
                            goals_found += 1
                            break
    
        if goals_found < 3:
            errors.append(f"[X] Expected at least 3 numbered list items referencing Sprint Goals, found {goals_found}")
        else:
            checks_passed.append(f"[C] Found at least 3 numbered list items referencing Sprint Goals ({goals_found})")
    
        # 6. Verify blue callout with '📈' icon and January 29 date
        blue_callout_found = False
    
        for block in blocks:
            if block.get("type") == "callout":
                block_order = block.get("order", 0)
                if block_order > goal_achievement_order:
                    props = block.get("properties", {})
                    bg_color = props.get("backgroundColor", "").lower()
                    icon = props.get("icon", "")
                    content = block.get("content", "")
                
                    if "blue" in bg_color and "📈" in icon:
                        # Check for January 29 date
                        if "january 29" in content.lower() or "jan 29" in content.lower():
                            blue_callout_found = True
                            break
    
        if not blue_callout_found:
            errors.append("[X] Callout with blue_background, '📈' icon, and 'January 29, 2024' date not found")
        else:
            checks_passed.append("[C] Callout with blue_background, '📈' icon, and 'January 29, 2024' date found")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: organize-archived-content-v2
# Description: Search for archived pages and organize them into a structured
# Archive 2024 page with subsections and explanatory callout
# =============================================================================
def _validate_agent_organize_archived_content(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate organization of archived content with:
    - Main 'Archive 2024' page with folder icon
    - Page marked as favorite
    - 3 subsection pages (Old Marketing, Legacy Documentation, Past Projects)
    - Archived pages redistributed as children under relevant subsections
    - Explanatory callout on main archive page
    
    Returns 1.0 only if ALL requirements are met, otherwise 0.0
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1 Query all pages and blocks from backend
    try:
        archive_page = _get_pages_by_filter(backend, {"title": "Archive 2024"})[0]
        archive_id = archive_page.get("_id")

        if not archive_page:
            errors.append("[X] Archive 2024 page not found")
        else:
            checks_passed.append("[C] Archive 2024 page found")

        archive_blocks = _get_blocks_by_filter(backend, {"pageId": archive_id})
    
        if not isinstance(archive_blocks, list):
            archive_blocks = []
    
        # 2. Check for folder icon
        icon = archive_page.get("icon")
        if not icon:
            errors.append("[X] Archive 2024 page does not have an icon")
        else:
            checks_passed.append("[C] Archive 2024 page has an icon")
    
        # Check if icon is folder-related (could be emoji or custom)
        icon_value = icon.get("value", "").lower() if isinstance(icon, dict) else str(icon).lower()
        if "folder" not in icon_value and "📁" not in icon_value and "🗂" not in icon_value:
            errors.append(f"[X] Archive 2024 page does not have a folder icon (found: {icon_value})")
        else:
            checks_passed.append(f"[C] Archive 2024 page has a folder icon (found: {icon_value})")
    
        # 3. Check if marked as favorite
        is_favorite = archive_page.get("isFavorite", False)
        if not is_favorite:
            errors.append("[X] Archive 2024 page is not marked as favorite")
        else:
            checks_passed.append("[C] Archive 2024 page is marked as favorite")
    
        # 4. Validate 3 subsection pages exist
        required_subsections = [
            "Old Marketing",
            "Legacy Documentation",
            "Past Projects"
        ]
    
        subsection_pages = _get_pages_by_filter(backend, {"parentId": archive_id})
    
        if len(subsection_pages) != 3:
            errors.append(f"[X] Expected 3 subsections under Archive 2024, found {len(subsection_pages)}")
        else:
            checks_passed.append(f"[C] Found 3 subsections under Archive 2024 as expected")

        for subsection_page in subsection_pages:
            if subsection_page.get("title") not in required_subsections:
                errors.append(f"[X] Expected subsection page {subsection_page.get('title')} to be in {required_subsections}")
            else:
                checks_passed.append(f"[C] Expected subsection page {subsection_page.get('title')} to be in {required_subsections}")

        # 5. Validate archived pages are redistributed under relevant subsections
        # Build mapping of subsection title -> subsection id
        subsection_id_map = {page.get("title"): page.get("_id") for page in subsection_pages}
    
        # Define expected redistribution: archived page titles -> expected subsection
        expected_redistribution = {
            "Old Marketing Campaign": "Old Marketing",
            "Old Brand Assets": "Old Marketing",
            "Deprecated API Docs": "Legacy Documentation",
            "Legacy Code Review": "Legacy Documentation",
            "Old Project Notes": "Past Projects",
        }
    
        # Check each archived page is now under the correct subsection
        redistributed_count = 0
        for archived_title, expected_subsection in expected_redistribution.items():
            archived_pages = _get_pages_by_filter(backend, {"title": archived_title})
            if not archived_pages:
                continue  # Page may not exist in this workspace
        
            archived_page = archived_pages[0]
            expected_parent_id = subsection_id_map.get(expected_subsection)
            actual_parent_id = archived_page.get("parentId")
        
            if actual_parent_id != expected_parent_id:
                errors.append(f"[X] Archived page '{archived_title}' is not under '{expected_subsection}' subsection (expected parentId: {expected_parent_id}, got: {actual_parent_id})")
            else:
                checks_passed.append(f"[C] Archived page '{archived_title}' is under '{expected_subsection}' subsection (expected parentId: {expected_parent_id}, got: {actual_parent_id})")
        
            redistributed_count += 1
    
        if redistributed_count == 0:
            errors.append("[X] No archived pages were redistributed under subsections")
        else:
            checks_passed.append("[C] archived pages were redistributed under subsections")
    
        # 6. Validate explanatory callout exists on main archive page
        archive_blocks = _get_blocks_by_filter(backend, {"pageId": archive_id})
    
        has_callout = False
        callout_content = ""
        for block in archive_blocks:
            if block.get("type") == "callout":
                has_callout = True
                callout_content = block.get("content", "")
                break
    
        if not has_callout:
            errors.append("[X] Archive 2024 page does not contain an explanatory callout block")
        else:
            checks_passed.append("[C] Archive 2024 page does contains an explanatory callout block")
    
        # Check callout mentions organization/archive
        callout_lower = callout_content.lower()
        if "organi" not in callout_lower and "archive" not in callout_lower:
            errors.append("[X] Callout does not explain archive organization structure")
        else:
            checks_passed.append("[C] Callout explain archive organization structure")
    
        # ALL requirements met!
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: create-team-onboarding-hub-v2
# Description: Create a comprehensive Team Onboarding hub with people icon,
# 4 subpages, structured content, favorite status, and parent-child relationship
# =============================================================================
def _validate_agent_create_team_onboarding_hub(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate Team Onboarding hub creation with:
    - Main 'Team Onboarding' page with people icon
    - 4 subpages: Getting Started Guide, Development Setup, Team Resources, First Week Tasks
    - Main hub contains heading1, paragraph, and bulletedList blocks
    - Hub marked as favorite
    - Hub is a child of 'Getting Started' page
    
    Returns 1.0 only if ALL requirements are met, otherwise 0.0
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Find the main 'Team Onboarding' page
    try:
        team_onboarding_pages = _get_pages_by_filter(backend, {"title": "Team Onboarding"})
        if not team_onboarding_pages:
            errors.append("[X] Team Onboarding page not found")
        else:
            checks_passed.append("[C] Team Onboarding page found")
    
        team_onboarding_page = team_onboarding_pages[0]
        team_onboarding_id = team_onboarding_page.get("_id")
    
        # 2. Check for people icon
        icon = team_onboarding_page.get("icon")
        if not icon:
            errors.append("[X] Team Onboarding page does not have an icon")
        else:
            checks_passed.append("[C] Team Onboarding page has an icon")
    
        # Check if icon is people-related (could be emoji or custom)
        icon_value = icon.get("value", "").lower() if isinstance(icon, dict) else str(icon).lower()
        people_emojis = ["👥", "👨", "👩", "🧑", "people", "person", "team", "user"]
        has_people_icon = any(emoji in icon_value for emoji in people_emojis)
    
        if not has_people_icon:
            errors.append(f"[X] Team Onboarding page does not have a people icon (found: {icon_value})")
        else:
            checks_passed.append(f"[C] Team Onboarding page has a people icon (found: {icon_value})")
    
        # 3. Check if marked as favorite
        is_favorite = team_onboarding_page.get("isFavorite", False)
        if not is_favorite:
            errors.append("[X] Team Onboarding page is not marked as favorite")
        else:
            checks_passed.append("[C] Team Onboarding page is marked as favorite")
    
        # 4. Validate 4 subpages exist as children
        required_subpages = [
            "Getting Started Guide",
            "Development Setup",
            "Team Resources",
            "First Week Tasks"
        ]
    
        child_pages = _get_pages_by_filter(backend, {"parentId": team_onboarding_id})
        child_titles = [p.get("title", "").lower() for p in child_pages]
    
        missing_subpages = []
        for required in required_subpages:
            if not any(required.lower() in title or title in required.lower() for title in child_titles):
                missing_subpages.append(required)
    
        if missing_subpages:
            errors.append(f"[X] Missing required subpages: {', '.join(missing_subpages)}")
        else:
            checks_passed.append(f"[C] has required subpages: {', '.join(missing_subpages)}")
    
        # 5. Validate main hub contains required block types
        hub_blocks = _get_blocks_by_filter(backend, {"pageId": team_onboarding_id})
    
        has_heading1 = False
        has_paragraph = False
        has_bulleted_list = False
    
        for block in hub_blocks:
            block_type = block.get("type", "")
            if block_type == "heading1":
                has_heading1 = True
            elif block_type == "paragraph":
                has_paragraph = True
            elif block_type == "bulletedList":
                has_bulleted_list = True
    
        if not has_heading1:
            errors.append("[X] Team Onboarding page does not contain a heading1 block")
        else:
            checks_passed.append("[C] Team Onboarding page does contains a heading1 block")
    
        if not has_paragraph:
            errors.append("[X] Team Onboarding page does not contain a paragraph block")
        else:
            checks_passed.append("[C] Team Onboarding page does contains a paragraph block")
    
        if not has_bulleted_list:
            errors.append("[X] Team Onboarding page does not contain a bulletedList block")
        else:
            checks_passed.append("[C] Team Onboarding page does contains a bulletedList block")
    
        # 6. Verify hub is a child of 'Getting Started' page
        getting_started_pages = _get_pages_by_filter(backend, {"title": "Getting Started"})
        if not getting_started_pages:
            errors.append("[X] Getting Started page not found")
        else:
            checks_passed.append("[C] Getting Started page found")
    
        getting_started_page = getting_started_pages[0]
    
        # Check if Team Onboarding is a child of Getting Started
        if team_onboarding_page.get("parentId") != getting_started_page.get("_id"):
            errors.append("[X] Team Onboarding page is not a child of 'Getting Started' page")
        else:
            checks_passed.append("[C] Team Onboarding page is a child of 'Getting Started' page")
    
        # ALL requirements met!
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: create-onboarding-hub-with-duplicated-template-v2
# Description: Create comprehensive onboarding hub by creating main hub page,
# duplicating a template, customizing it, and populating with structured content
# =============================================================================
def _validate_agent_create_onboarding_hub_with_duplicated_template(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate onboarding hub creation with template duplication:
    - Main 'Team Onboarding Hub' page with welcome icon
    - 'Weekly Standup Template' duplicated as 'New Hire First Week Guide' with star icon
    - Guide contains at least 2 heading blocks, 1 todo checklist, and 1 callout
    - Hub page marked as favorite
    
    Returns 1.0 only if ALL requirements are met, otherwise 0.0
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Find the main 'Team Onboarding Hub' page
    try:
        hub_pages = _get_pages_by_filter(backend, {"title": "Team Onboarding Hub"})
        if not hub_pages:
            errors.append("[X] Team Onboarding Hub page not found")
        else:
            checks_passed.append("[C] Team Onboarding Hub page found")
    
        hub_page = hub_pages[0]
    
        # 2. Check for welcome icon
        icon = hub_page.get("icon")
        if not icon:
            errors.append("[X] Team Onboarding Hub page does not have an icon")
        else:
            checks_passed.append("[C] Team Onboarding Hub page has an icon")
    
        # Check if icon is welcome-related (could be emoji or custom)
        icon_value = icon.get("value", "").lower() if isinstance(icon, dict) else str(icon).lower()
        welcome_emojis = ["👋", "🙏", "🤗", "welcome", "wave", "hand", "hello", "hi"]
        has_welcome_icon = any(emoji in icon_value for emoji in welcome_emojis)
    
        if not has_welcome_icon:
            errors.append(f"[X] Team Onboarding Hub page does not have a welcome icon (found: {icon_value})")
        else:
            checks_passed.append(f"[C] Team Onboarding Hub page has a welcome icon (found: {icon_value})")
    
        # 3. Check if marked as favorite
        is_favorite = hub_page.get("isFavorite", False)
        if not is_favorite:
            errors.append("[X] Team Onboarding Hub page is not marked as favorite")
        else:
            checks_passed.append("[C] Team Onboarding Hub page is marked as favorite")
    
        # 4. Find the 'New Hire First Week Guide' page (duplicated template)
        guide_pages = _get_pages_by_filter(backend, {"title": "New Hire First Week Guide"})
        if not guide_pages:
            errors.append("[X] New Hire First Week Guide page not found (template should be duplicated and renamed)")
        else:
            checks_passed.append("[C] New Hire First Week Guide page found (template should be duplicated and renamed)")
    
        guide_page = guide_pages[0]
        guide_id = guide_page.get("_id")
    
        # 5. Check for star icon on guide
        guide_icon = guide_page.get("icon")
        if not guide_icon:
            errors.append("[X] New Hire First Week Guide page does not have an icon")
        else:
            checks_passed.append("[C] New Hire First Week Guide page has an icon")
    
        # Check if icon is star-related
        guide_icon_value = guide_icon.get("value", "").lower() if isinstance(guide_icon, dict) else str(guide_icon).lower()
        star_emojis = ["⭐", "🌟", "✨", "star"]
        has_star_icon = any(emoji in guide_icon_value for emoji in star_emojis)
    
        if not has_star_icon:
            errors.append(f"[X] New Hire First Week Guide page does not have a star icon (found: {guide_icon_value})")
        else:
            checks_passed.append(f"[C] New Hire First Week Guide page has a star icon (found: {guide_icon_value})")
    
        # 6. Validate guide contains required block types
        guide_blocks = _get_blocks_by_filter(backend, {"pageId": guide_id})
    
        if len(guide_blocks) < 4:
            errors.append(f"[X] New Hire First Week Guide needs at least 4 blocks (2 headings, 1 todo, 1 callout), found {len(guide_blocks)}")
        else:
            checks_passed.append(f"[C] New Hire First Week Guide needs at least 4 blocks (2 headings, 1 todo, 1 callout), found {len(guide_blocks)}")
    
        heading_count = 0
        has_todo = False
        has_callout = False
        todo_item_count = 0
    
        for block in guide_blocks:
            block_type = block.get("type", "")
            if block_type in ["heading1", "heading2", "heading3"]:
                heading_count += 1
            elif block_type == "todo":
                has_todo = True
                todo_item_count += 1
            elif block_type == "callout":
                has_callout = True
    
        if heading_count < 2:
            errors.append(f"[X] New Hire First Week Guide needs at least 2 heading blocks, found {heading_count}")
        else:
            checks_passed.append(f"[C] New Hire First Week Guide needs at least 2 heading blocks, found {heading_count}")
    
        if not has_todo:
            errors.append("[X] New Hire First Week Guide does not contain any todo checklist blocks")
        else:
            checks_passed.append("[C] New Hire First Week Guide does contains any todo checklist blocks")
    
        if todo_item_count < 2:
            errors.append(f"[X] New Hire First Week Guide needs at least 2 todo items in checklist, found {todo_item_count}")
        else:
            checks_passed.append(f"[C] New Hire First Week Guide needs at least 2 todo items in checklist, found {todo_item_count}")
    
        if not has_callout:
            errors.append("[X] New Hire First Week Guide does not contain a callout block")
        else:
            checks_passed.append("[C] New Hire First Week Guide does contains a callout block")
    
        # 7. Verify the Weekly Standup Template still exists (not deleted, just duplicated)
        template_pages = _get_pages_by_filter(backend, {"title": "Weekly Standup Template"})
        if not template_pages:
            errors.append("[X] Weekly Standup Template was deleted instead of duplicated (should still exist)")
        else:
            checks_passed.append("[C] Weekly Standup Template was deleted instead of duplicated (should still exist)")
    
        # ALL requirements met!
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: identify-sparse-content-pages-v2
# Description: Identify top-level pages with fewer than 3 blocks and create a
# Content Review Queue page with todo items linking to those sparse pages
# =============================================================================
def _validate_agent_identify_sparse_content_pages(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate Content Review Queue creation with:
    - 'Content Review Queue' page exists with ⚡ icon
    - Page is marked as favorite
    - Quote block at top with text 'Pages requiring immediate content development'
    - Todo items linking to top-level pages that have fewer than 3 blocks
    - Only top-level pages (those without a parent) are analyzed
    
    Returns 1.0 only if ALL requirements are met, otherwise 0.0
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Find the 'Content Review Queue' page
    try:
        review_queue_pages = _get_pages_by_filter(backend, {"title": "Content Review Queue"})
        if not review_queue_pages:
            errors.append("[X] Content Review Queue page not found")
        else:
            checks_passed.append("[C] Content Review Queue page found")
    
        review_queue_page = review_queue_pages[0]
        review_queue_id = review_queue_page.get("_id")
    
        # 2. Check for ⚡ (lightning/zap) icon
        icon = review_queue_page.get("icon")
        if not icon:
            errors.append("[X] Content Review Queue page does not have an icon")
        else:
            checks_passed.append("[C] Content Review Queue page has an icon")
    
        # Check if icon is lightning/zap-related
        icon_value = icon.get("value", "").lower() if isinstance(icon, dict) else str(icon).lower()
        lightning_emojis = ["⚡", "🔌", "lightning", "zap", "bolt", "electric"]
        has_lightning_icon = any(emoji in icon_value for emoji in lightning_emojis)
    
        if not has_lightning_icon:
            errors.append(f"[X] Content Review Queue page does not have a ⚡ icon (found: {icon_value})")
        else:
            checks_passed.append(f"[C] Content Review Queue page has a ⚡ icon (found: {icon_value})")
    
        # 3. Check if marked as favorite
        is_favorite = review_queue_page.get("isFavorite", False)
        if not is_favorite:
            errors.append("[X] Content Review Queue page is not marked as favorite")
        else:
            checks_passed.append("[C] Content Review Queue page is marked as favorite")
    
        # 4. Get blocks for the Content Review Queue page
        review_queue_blocks = _get_blocks_by_filter(backend, {"pageId": review_queue_id})
    
        if len(review_queue_blocks) < 1:
            errors.append("[X] Content Review Queue page has no content blocks")
        else:
            checks_passed.append("[C] Content Review Queue page has content blocks")
    
        # 5. Validate quote block at top with specified text
        # The first block must be a quote block
        expected_quote_text = "pages requiring immediate content development"
    
        first_block = review_queue_blocks[0]
        if first_block.get("type") != "quote":
            errors.append(f"[X] First block must be a quote block, but found '{first_block.get('type')}' instead")
        else:
            checks_passed.append(f"[C] First block must be a quote block, but found '{first_block.get('type')}' instead")
    
        quote_content = first_block.get("content", "").lower()
        if expected_quote_text not in quote_content:
            errors.append(f"[X] Quote block does not contain the required text: 'Pages requiring immediate content development'")
        else:
            checks_passed.append(f"[C] Quote block does contains the required text: 'Pages requiring immediate content development'")
    
        # 6. Identify top-level pages (those without a parent)
        # Query pages with no parentId - need to get all pages for this check
        all_pages = _get_pages_by_filter(backend, {})
        top_level_pages = [p for p in all_pages if not p.get("parentId") and p.get("_id") != review_queue_id]
    
        # 7. Find top-level pages with fewer than 3 blocks
        sparse_pages = []
        for page in top_level_pages:
            page_id = page.get("_id")
            page_blocks = _get_blocks_by_filter(backend, {"pageId": page_id})
            if len(page_blocks) < 3:
                sparse_pages.append(page)
    
        # 8. Validate todo items exist for sparse pages
        todo_blocks = [b for b in review_queue_blocks if b.get("type") == "todo"]
    
        if len(sparse_pages) > 0 and len(todo_blocks) == 0:
            errors.append(f"[X] Found {len(sparse_pages)} sparse pages but no todo items in Content Review Queue")
        else:
            checks_passed.append(f"[C] Found {len(sparse_pages)} sparse pages but todo items in Content Review Queue")
    
        # Check that each sparse page has a corresponding todo item
        # Todo items should contain the page title (as a link or reference)
        todo_contents = []
        for todo in todo_blocks:
            content = todo.get("content", "").lower()
            todo_contents.append(content)
    
        # Verify each sparse page is mentioned in a todo
        pages_with_todos = 0
        missing_todos = []
        for sparse_page in sparse_pages:
            page_title = sparse_page.get("title", "")
            page_title_lower = page_title.lower()
            found_in_todo = any(page_title_lower in content for content in todo_contents)
            if found_in_todo:
                pages_with_todos += 1
            else:
                missing_todos.append(page_title)
    
        if len(sparse_pages) > 0 and pages_with_todos == 0:
            errors.append(f"[X] No todo items reference the sparse pages. Expected todos for: {', '.join([p.get('title', '') for p in sparse_pages])}")
        else:
            checks_passed.append(f"[C] todo items reference the sparse pages. Expected todos for: {', '.join([p.get('title', '') for p in sparse_pages])}")
    
        if len(missing_todos) > 0:
            errors.append(f"[X] Missing todo items for sparse pages: {', '.join(missing_todos)}")
        else:
            checks_passed.append(f"[C] has todo items for sparse pages: {', '.join(missing_todos)}")
    
        # ALL requirements met!
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: organize-meeting-archive-v2
# Description: Search for meeting pages (Sprint/Retrospective) and organize them
# into a Meeting Archive - Q1 2024 page with calendar icon, structured sections,
# and summary
# =============================================================================
def _validate_agent_organize_meeting_archive(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate meeting archive organization with:
    - Main 'Meeting Archive - Q1 2024' page with calendar icon
    - Page marked as favorite
    - At least 2 meeting-related pages moved as children
    - Archive page contains heading sections and bulleted list summary
    - Original meeting pages retain their content and metadata
    
    Returns 1.0 only if ALL requirements are met, otherwise 0.0
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Find the main 'Meeting Archive - Q1 2024' page
    try:
        archive_pages = _get_pages_by_filter(backend, {"title": "Meeting Archive - Q1 2024"})
        if not archive_pages:
            errors.append("[X] Meeting Archive - Q1 2024 page not found")
        else:
            checks_passed.append("[C] Meeting Archive - Q1 2024 page found")
    
        archive_page = archive_pages[0]
        archive_id = archive_page.get("_id")
    
        # 2. Check for calendar icon
        icon = archive_page.get("icon")
        if not icon:
            errors.append("[X] Meeting Archive - Q1 2024 page does not have an icon")
        else:
            checks_passed.append("[C] Meeting Archive - Q1 2024 page has an icon")
    
        # Check if icon is calendar-related (could be emoji or custom)
        icon_value = icon.get("value", "").lower() if isinstance(icon, dict) else str(icon).lower()
        calendar_emojis = ["📅", "📆", "🗓", "calendar", "date"]
        has_calendar_icon = any(emoji in icon_value for emoji in calendar_emojis)
    
        if not has_calendar_icon:
            errors.append(f"[X] Meeting Archive - Q1 2024 page does not have a calendar icon (found: {icon_value})")
        else:
            checks_passed.append(f"[C] Meeting Archive - Q1 2024 page has a calendar icon (found: {icon_value})")
    
        # 3. Check if marked as favorite
        is_favorite = archive_page.get("isFavorite", False)
        if not is_favorite:
            errors.append("[X] Meeting Archive - Q1 2024 page is not marked as favorite")
        else:
            checks_passed.append("[C] Meeting Archive - Q1 2024 page is marked as favorite")
    
        # 4. Find meeting-related pages (children of archive with Sprint or Retrospective in title)
        child_pages = _get_pages_by_filter(backend, {"parentId": archive_id})
    
        meeting_keywords = ["sprint", "retrospective"]
        meeting_pages = []
        for child in child_pages:
            child_title = child.get("title", "").lower()
            if any(keyword in child_title for keyword in meeting_keywords):
                meeting_pages.append(child)
    
        if len(meeting_pages) < 2:
            errors.append(f"[X] Expected at least 2 meeting-related pages as children of archive, found {len(meeting_pages)}")
        else:
            checks_passed.append(f"[C] Found at least 2 meeting-related pages as children of archive ({len(meeting_pages)})")
    
        # 5. Validate archive page contains structured content
        archive_blocks = _get_blocks_by_filter(backend, {"pageId": archive_id})
    
        if len(archive_blocks) < 2:
            errors.append(f"[X] Archive page needs at least 2 blocks (heading + bulleted list), found {len(archive_blocks)}")
        else:
            checks_passed.append(f"[C] Archive page needs at least 2 blocks (heading + bulleted list), found {len(archive_blocks)}")
    
        # Check for heading block
        has_heading = False
        has_bulleted_list = False
        bulleted_list_count = 0
    
        for block in archive_blocks:
            block_type = block.get("type", "")
            if block_type in ["heading1", "heading2", "heading3"]:
                has_heading = True
            elif block_type == "bulletedList":
                has_bulleted_list = True
                bulleted_list_count += 1
    
        if not has_heading:
            errors.append("[X] Archive page does not contain any heading blocks")
        else:
            checks_passed.append("[C] Archive page does contains any heading blocks")
    
        if not has_bulleted_list:
            errors.append("[X] Archive page does not contain a bulleted list summary")
        else:
            checks_passed.append("[C] Archive page does contains a bulleted list summary")
    
        if bulleted_list_count < 2:
            errors.append(f"[X] Archive page needs at least 2 bulleted list items for summary, found {bulleted_list_count}")
        else:
            checks_passed.append(f"[C] Archive page needs at least 2 bulleted list items for summary, found {bulleted_list_count}")
    
        # 6. Validate that moved meeting pages retain their content
        pages_with_content = 0
        for meeting_page in meeting_pages:
            meeting_page_id = meeting_page.get("_id")
            meeting_blocks = _get_blocks_by_filter(backend, {"pageId": meeting_page_id})
            # Pages should have some content (at least 1 block to show they retain content)
            if len(meeting_blocks) >= 1:
                pages_with_content += 1
    
        if pages_with_content < len(meeting_pages):
            errors.append(f"[X] Some meeting pages lost their content during move ({pages_with_content}/{len(meeting_pages)} retained content)")
        else:
            checks_passed.append(f"[C] Some meeting pages lost their content during move ({pages_with_content}/{len(meeting_pages)} retained content)")
    
        # ALL requirements met!
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: add-ruby-section-to-code-examples-v2
# Description: Navigate to Code Examples Repository page and add a Ruby Examples
# section with specific positioning, code block, and description. Also add a
# Language Statistics section at the end with a gray callout.
# =============================================================================
def _validate_agent_add_ruby_section_to_code_examples(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate Ruby section addition to Code Examples Repository with:
    - 'Code Examples Repository' page exists
    - 'Ruby Examples' heading_2 appears AFTER Python section's description paragraph
      and BEFORE 'Typescript Examples' heading
    - Ruby code block with language='ruby' and exact specified content
    - Ruby description paragraph matching format of other sections
    - 'Language Statistics' heading_2 at the very end
    - Gray callout under Language Statistics with paragraph containing count
    
    Returns 1.0 only if ALL requirements are met, otherwise 0.0
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Find the 'Code Examples Repository' page
    try:
        code_examples_pages = _get_pages_by_filter(backend, {"title": "Code Examples Repository"})
        if not code_examples_pages:
            errors.append("[X] Code Examples Repository page not found")
        else:
            checks_passed.append("[C] Code Examples Repository page found")
    
        code_examples_page = code_examples_pages[0]
        code_examples_id = code_examples_page.get("_id")
    
        # 2. Get all blocks for the Code Examples Repository page
        page_blocks = _get_blocks_by_filter(backend, {"pageId": code_examples_id})
    
        if len(page_blocks) < 5:
            errors.append(f"[X] Code Examples Repository needs sufficient blocks for Ruby section and Language Statistics, found {len(page_blocks)}")
        else:
            checks_passed.append(f"[C] Code Examples Repository needs sufficient blocks for Ruby section and Language Statistics, found {len(page_blocks)}")
    
        # 3. Find key blocks: Python paragraph, Ruby heading, Typescript heading
        python_paragraph_idx = -1
        ruby_heading_idx = -1
        typescript_heading_idx = -1
        ruby_code_block_idx = -1
        ruby_description_idx = -1
        language_stats_heading_idx = -1
        language_stats_callout_idx = -1
    
        expected_ruby_code = "class Calculator\n def self.fibonacci(n)\n return n if n <= 1\n fibonacci(n - 1) + fibonacci(n - 2)\n end\nend\n\nputs Calculator.fibonacci(10)"
    
        for idx, block in enumerate(page_blocks):
            block_type = block.get("type", "")
            block_content = block.get("content", "")
        
            # Find Python description paragraph
            if block_type == "paragraph" and "common python pattern" in block_content.lower():
                python_paragraph_idx = idx
        
            # Find Ruby Examples heading
            if block_type == "heading2" and "ruby examples" in block_content.lower():
                ruby_heading_idx = idx
        
            # Find Typescript Examples heading
            if block_type == "heading2" and "typescript examples" in block_content.lower():
                typescript_heading_idx = idx
        
            # Find Ruby code block
            if block_type == "code":
                block_properties = block.get("properties", {})
                if isinstance(block_properties, dict) and block_properties.get("language") == "ruby":
                    # Check content matches
                    if block_content.strip() == expected_ruby_code.strip():
                        ruby_code_block_idx = idx
        
            # Find Ruby description paragraph
            if block_type == "paragraph" and "common ruby pattern" in block_content.lower():
                ruby_description_idx = idx
        
            # Find Language Statistics heading
            if block_type == "heading2" and "language statistics" in block_content.lower():
                language_stats_heading_idx = idx
        
            # Find Language Statistics callout
            if block_type == "callout":
                block_properties = block.get("properties", {})
                background_color = block_properties.get("backgroundColor", "") if isinstance(block_properties, dict) else ""
                if "gray" in background_color.lower() or background_color == "gray":
                    if "total programming languages covered: 9" in block_content.lower():
                        language_stats_callout_idx = idx
    
        # 4. Validate Ruby Examples heading exists
        if ruby_heading_idx == -1:
            errors.append("[X] Ruby Examples heading_2 not found")
        else:
            checks_passed.append("[C] Ruby Examples heading_2 found")
    
        # 5. Validate Ruby heading is positioned correctly
        if python_paragraph_idx == -1:
            errors.append("[X] Python section's description paragraph ('Common python pattern for production code.') not found")
        else:
            checks_passed.append("[C] Python section's description paragraph ('Common python pattern for production code.') found")
    
        if typescript_heading_idx == -1:
            errors.append("[X] Typescript Examples heading not found")
        else:
            checks_passed.append("[C] Typescript Examples heading found")
    
        # Ruby heading should be AFTER Python paragraph and BEFORE Typescript heading
        if not (python_paragraph_idx < ruby_heading_idx < typescript_heading_idx):
            errors.append(f"[X] Ruby Examples heading not positioned correctly. Expected: Python paragraph (idx {python_paragraph_idx}) < Ruby heading (idx {ruby_heading_idx}) < Typescript heading (idx {typescript_heading_idx})")
        else:
            checks_passed.append(f"[C] Ruby Examples heading positioned correctly. Expected: Python paragraph (idx {python_paragraph_idx}) < Ruby heading (idx {ruby_heading_idx}) < Typescript heading (idx {typescript_heading_idx})")
    
        # 6. Validate Ruby code block exists with correct content and language
        if ruby_code_block_idx == -1:
            errors.append("[X] Ruby code block with correct language property and exact content not found")
        else:
            checks_passed.append("[C] Ruby code block with correct language property and exact content found")
    
        # Code block should be after Ruby heading
        if ruby_code_block_idx <= ruby_heading_idx:
            errors.append(f"[X] Ruby code block should appear after Ruby heading (heading at {ruby_heading_idx}, code at {ruby_code_block_idx})")
        else:
            checks_passed.append(f"[C] Ruby code block should appear after Ruby heading (heading at {ruby_heading_idx}, code at {ruby_code_block_idx})")
    
        # 7. Validate Ruby description paragraph
        if ruby_description_idx == -1:
            errors.append("[X] Ruby description paragraph ('Common ruby pattern for production code.') not found")
        else:
            checks_passed.append("[C] Ruby description paragraph ('Common ruby pattern for production code.') found")
    
        # Description should be after code block
        if ruby_description_idx <= ruby_code_block_idx:
            errors.append(f"[X] Ruby description paragraph should appear after code block (code at {ruby_code_block_idx}, description at {ruby_description_idx})")
        else:
            checks_passed.append(f"[C] Ruby description paragraph should appear after code block (code at {ruby_code_block_idx}, description at {ruby_description_idx})")
    
        # 8. Validate Language Statistics section at the end
        if language_stats_heading_idx == -1:
            errors.append("[X] Language Statistics heading_2 not found")
        else:
            checks_passed.append("[C] Language Statistics heading_2 found")
    
        # Language Statistics should be near the end (after Ruby section and Typescript section)
        if language_stats_heading_idx < typescript_heading_idx:
            errors.append(f"[X] Language Statistics heading should be at the end, after all language sections (Typescript at {typescript_heading_idx}, Language Statistics at {language_stats_heading_idx})")
        else:
            checks_passed.append(f"[C] Language Statistics heading should be at the end, after all language sections (Typescript at {typescript_heading_idx}, Language Statistics at {language_stats_heading_idx})")
    
        # 9. Validate gray callout with count
        if language_stats_callout_idx == -1:
            errors.append("[X] Gray callout with 'Total programming languages covered: 9' not found under Language Statistics")
        else:
            checks_passed.append("[C] Gray callout with 'Total programming languages covered: 9' found under Language Statistics")
    
        # Callout should be after Language Statistics heading
        if language_stats_callout_idx <= language_stats_heading_idx:
            errors.append(f"[X] Language Statistics callout should appear after the heading (heading at {language_stats_heading_idx}, callout at {language_stats_callout_idx})")
        else:
            checks_passed.append(f"[C] Language Statistics callout should appear after the heading (heading at {language_stats_heading_idx}, callout at {language_stats_callout_idx})")
    
        # ALL requirements met!
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: create-project-management-hub-v2
# Description: Create a comprehensive Project Hub page with building icon,
# 3 main sections (Active Projects, Planning Templates, Guidelines),
# duplicate Weekly Standup Template and move under hub, mark as favorite
# =============================================================================
def _validate_agent_create_project_management_hub_2(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate Project Hub creation with:
    - Main 'Project Hub' page with building icon
    - Page marked as favorite
    - 3 main sections: Active Projects, Planning Templates, Guidelines
    - At least 3 heading blocks and 2 divider blocks
    - Duplicated 'Weekly Standup Template' moved under hub
    
    Returns 1.0 only if ALL requirements are met, otherwise 0.0
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Find the main 'Project Hub' page
    try:
        project_hub_pages = _get_pages_by_filter(backend, {"title": "Project Hub"})
        if not project_hub_pages:
            errors.append("[X] Project Hub page not found")
        else:
            checks_passed.append("[C] Project Hub page found")
    
        project_hub_page = project_hub_pages[0]
        project_hub_id = project_hub_page.get("_id")
    
        # 2. Check for building icon
        icon = project_hub_page.get("icon")
        if not icon:
            errors.append("[X] Project Hub page does not have an icon")
        else:
            checks_passed.append("[C] Project Hub page has an icon")
    
        # Check if icon is building-related (could be emoji or custom)
        icon_value = icon.get("value", "").lower() if isinstance(icon, dict) else str(icon).lower()
        building_emojis = ["🏗", "🏢", "🏛", "🏭", "🏘", "building", "construct", "office"]
        has_building_icon = any(emoji in icon_value for emoji in building_emojis)
    
        if not has_building_icon:
            errors.append(f"[X] Project Hub page does not have a building icon (found: {icon_value})")
        else:
            checks_passed.append(f"[C] Project Hub page has a building icon (found: {icon_value})")
    
        # 3. Check if marked as favorite
        is_favorite = project_hub_page.get("isFavorite", False)
        if not is_favorite:
            errors.append("[X] Project Hub page is not marked as favorite")
        else:
            checks_passed.append("[C] Project Hub page is marked as favorite")
    
        # 4. Get all blocks for the Project Hub page
        hub_blocks = _get_blocks_by_filter(backend, {"pageId": project_hub_id})
    
        if len(hub_blocks) < 5:
            errors.append(f"[X] Project Hub needs at least 5 blocks (3 headings + 2 dividers), found {len(hub_blocks)}")
        else:
            checks_passed.append(f"[C] Project Hub needs at least 5 blocks (3 headings + 2 dividers), found {len(hub_blocks)}")
    
        # 5. Count heading blocks and divider blocks
        heading_count = 0
        divider_count = 0
        required_sections = ["active projects", "planning templates", "guidelines"]
        found_sections = []
    
        for block in hub_blocks:
            block_type = block.get("type", "")
            block_content = block.get("content", "").lower()
        
            if block_type in ["heading1", "heading2", "heading3"]:
                heading_count += 1
                # Check if this heading matches one of our required sections
                for section in required_sections:
                    if section in block_content:
                        found_sections.append(section)
        
            elif block_type == "divider":
                divider_count += 1
    
        if heading_count < 3:
            errors.append(f"[X] Project Hub needs at least 3 heading blocks, found {heading_count}")
        else:
            checks_passed.append(f"[C] Project Hub needs at least 3 heading blocks, found {heading_count}")
    
        if divider_count < 2:
            errors.append(f"[X] Project Hub needs at least 2 divider blocks, found {divider_count}")
        else:
            checks_passed.append(f"[C] Project Hub needs at least 2 divider blocks, found {divider_count}")
    
        # 6. Verify all 3 required sections are present
        missing_sections = [s for s in required_sections if s not in found_sections]
        if missing_sections:
            errors.append(f"[X] Project Hub missing required sections: {', '.join(missing_sections)}")
        else:
            checks_passed.append(f"[C] Project Hub has required sections: {', '.join(missing_sections)}")
    
        # 7. Find duplicated Weekly Standup Template as a child of Project Hub
        # Look for pages that are children of Project Hub
        child_pages = _get_pages_by_filter(backend, {"parentId": project_hub_id})
    
        # Check if any child has "Weekly Standup Template" in title
        # (could be exact match or "Weekly Standup Template (Copy)" or similar)
        has_standup_template = False
        standup_template_title = ""
        for child in child_pages:
            child_title = child.get("title", "")
            child_title_lower = child_title.lower()
            if "weekly standup template" in child_title_lower:
                has_standup_template = True
                standup_template_title = child_title
                break
    
        if not has_standup_template:
            errors.append("[X] Duplicated Weekly Standup Template not found as child of Project Hub")
        else:
            checks_passed.append("[C] Duplicated Weekly Standup Template found as child of Project Hub")
    
        # 8. Verify the original Weekly Standup Template still exists (not deleted, just duplicated)
        original_templates = _get_pages_by_filter(backend, {"title": "Weekly Standup Template"})
        if not original_templates:
            # It's possible the duplicated one kept the exact name and the original was renamed/deleted
            # Check if there are at least 1 page with "Weekly Standup Template" in the name
            if len(child_pages) < 1:
                errors.append("[X] Weekly Standup Template was not properly duplicated (no template pages found)")
            else:
                checks_passed.append("[C] Weekly Standup Template was properly duplicated (template pages found)")
    
        # ALL requirements met!
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: create-retrospective-workflow-v2
# Description: Search for existing retrospective pages, create a comprehensive
# Retrospective Center with mirror icon, 3 main sections, a template sub-page
# with structured sections and todo blocks, duplicate the template, and mark as favorite
# =============================================================================
def _validate_agent_create_retrospective_workflow(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate retrospective workflow creation with:
    - Main 'Retrospective Center' page with mirror icon
    - Page marked as favorite
    - 3 main sections: Current Sprint, Past Retrospectives, Action Items (using headings)
    - 'Sprint Retrospective Template' sub-page with structured sections
    - Template contains: What Went Well, What Could Improve, Action Items (using headings and todo blocks)
    - Duplicated 'Q1 2025 Retrospective' created
    - At least 6 heading blocks total across pages
    - Multiple todo blocks across pages
    
    Returns 1.0 only if ALL requirements are met, otherwise 0.0
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Find the main 'Retrospective Center' page
    try:
        retro_center_pages = _get_pages_by_filter(backend, {"title": "Retrospective Center"})
        if not retro_center_pages:
            errors.append("[X] Retrospective Center page not found")
        else:
            checks_passed.append("[C] Retrospective Center page found")
    
        retro_center_page = retro_center_pages[0]
        retro_center_id = retro_center_page.get("_id")
    
        # 2. Check for mirror icon
        icon = retro_center_page.get("icon")
        if not icon:
            errors.append("[X] Retrospective Center page does not have an icon")
        else:
            checks_passed.append("[C] Retrospective Center page has an icon")
    
        # Check if icon is mirror-related (could be emoji or custom)
        icon_value = icon.get("value", "").lower() if isinstance(icon, dict) else str(icon).lower()
        mirror_emojis = ["🪞", "mirror", "reflect"]
        has_mirror_icon = any(emoji in icon_value for emoji in mirror_emojis)
    
        if not has_mirror_icon:
            errors.append(f"[X] Retrospective Center page does not have a mirror icon (found: {icon_value})")
        else:
            checks_passed.append(f"[C] Retrospective Center page has a mirror icon (found: {icon_value})")
    
        # 3. Check if marked as favorite
        is_favorite = retro_center_page.get("isFavorite", False)
        if not is_favorite:
            errors.append("[X] Retrospective Center page is not marked as favorite")
        else:
            checks_passed.append("[C] Retrospective Center page is marked as favorite")
    
        # 4. Get all blocks for the Retrospective Center page
        center_blocks = _get_blocks_by_filter(backend, {"pageId": retro_center_id})
    
        if len(center_blocks) < 3:
            errors.append(f"[X] Retrospective Center needs at least 3 heading blocks for main sections, found {len(center_blocks)} total blocks")
        else:
            checks_passed.append(f"[C] Retrospective Center needs at least 3 heading blocks for main sections, found {len(center_blocks)} total blocks")
    
        # 5. Validate 3 main sections exist in center page
        required_sections = ["current sprint", "past retrospectives", "action items"]
        found_sections = []
        center_heading_count = 0
    
        for block in center_blocks:
            block_type = block.get("type", "")
            block_content = block.get("content", "").lower()
        
            if block_type in ["heading1", "heading2", "heading3"]:
                center_heading_count += 1
                # Check if this heading matches one of our required sections
                for section in required_sections:
                    if section in block_content:
                        found_sections.append(section)
    
        # Verify all 3 required sections are present
        missing_sections = [s for s in required_sections if s not in found_sections]
        if missing_sections:
            errors.append(f"[X] Retrospective Center missing required sections: {', '.join(missing_sections)}")
        else:
            checks_passed.append(f"[C] Retrospective Center has required sections: {', '.join(missing_sections)}")
    
        # 6. Find the 'Sprint Retrospective Template' sub-page
        template_pages = _get_pages_by_filter(backend, {"title": "Sprint Retrospective Template"})
        if not template_pages:
            errors.append("[X] Sprint Retrospective Template sub-page not found")
        else:
            checks_passed.append("[C] Sprint Retrospective Template sub-page found")
    
        template_page = template_pages[0]
        template_id = template_page.get("_id")
    
        # 7. Verify template is a child of Retrospective Center
        if template_page.get("parentId") != retro_center_id:
            errors.append("[X] Sprint Retrospective Template is not a child of Retrospective Center")
        else:
            checks_passed.append("[C] Sprint Retrospective Template is a child of Retrospective Center")
    
        # 8. Validate template contains required sections with headings and todo blocks
        template_blocks = _get_blocks_by_filter(backend, {"pageId": template_id})
    
        if len(template_blocks) < 3:
            errors.append(f"[X] Sprint Retrospective Template needs structured sections with headings and todos, found {len(template_blocks)} blocks")
        else:
            checks_passed.append(f"[C] Sprint Retrospective Template needs structured sections with headings and todos, found {len(template_blocks)} blocks")
    
        template_required_sections = ["what went well", "what could improve", "action items"]
        template_found_sections = []
        template_heading_count = 0
        template_todo_count = 0
    
        for block in template_blocks:
            block_type = block.get("type", "")
            block_content = block.get("content", "").lower()
        
            if block_type in ["heading1", "heading2", "heading3"]:
                template_heading_count += 1
                # Check if this heading matches one of our required sections
                for section in template_required_sections:
                    if section in block_content:
                        template_found_sections.append(section)
            elif block_type == "todo":
                template_todo_count += 1
    
        # Verify all 3 required sections are present in template
        missing_template_sections = [s for s in template_required_sections if s not in template_found_sections]
        if missing_template_sections:
            errors.append(f"[X] Sprint Retrospective Template missing required sections: {', '.join(missing_template_sections)}")
        else:
            checks_passed.append(f"[C] Sprint Retrospective Template has required sections: {', '.join(missing_template_sections)}")
    
        if template_todo_count < 1:
            errors.append("[X] Sprint Retrospective Template does not contain any todo blocks")
        else:
            checks_passed.append("[C] Sprint Retrospective Template does contains any todo blocks")
    
        # 9. Find the duplicated 'Q1 2025 Retrospective' page
        q1_retro_pages = _get_pages_by_filter(backend, {"title": "Q1 2025 Retrospective"})
        if not q1_retro_pages:
            errors.append("[X] Q1 2025 Retrospective page not found (template should be duplicated)")
        else:
            checks_passed.append("[C] Q1 2025 Retrospective page found (template should be duplicated)")
    
        q1_retro_page = q1_retro_pages[0]
        q1_retro_id = q1_retro_page.get("_id")
    
        # 10. Validate Q1 2025 Retrospective has content (to prove it was duplicated)
        q1_retro_blocks = _get_blocks_by_filter(backend, {"pageId": q1_retro_id})
    
        if len(q1_retro_blocks) < 1:
            errors.append("[X] Q1 2025 Retrospective page is empty (should contain duplicated content from template)")
        else:
            checks_passed.append("[C] Q1 2025 Retrospective page is empty (should contain duplicated content from template)")
    
        # Count headings in Q1 retro
        q1_heading_count = 0
        q1_todo_count = 0
        for block in q1_retro_blocks:
            block_type = block.get("type", "")
            if block_type in ["heading1", "heading2", "heading3"]:
                q1_heading_count += 1
            elif block_type == "todo":
                q1_todo_count += 1
    
        # 11. Validate total heading count across all pages (at least 6)
        total_heading_count = center_heading_count + template_heading_count + q1_heading_count
    
        if total_heading_count < 6:
            errors.append(f"[X] Expected at least 6 heading blocks across all pages, found {total_heading_count} (Center: {center_heading_count}, Template: {template_heading_count}, Q1: {q1_heading_count})")
        else:
            checks_passed.append(f"[C] Found at least 6 heading blocks across all pages ({total_heading_count} (Center: {center_heading_count}, Template: {template_heading_count}, Q1: {q1_heading_count}))")
    
        # 12. Validate multiple todo blocks across pages
        total_todo_count = template_todo_count + q1_todo_count
    
        if total_todo_count < 2:
            errors.append(f"[X] Expected multiple todo blocks across pages, found {total_todo_count}")
        else:
            checks_passed.append(f"[C] Expected multiple todo blocks across pages, found {total_todo_count}")
    
        # ALL requirements met!
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: create-content-archive-system-v2
# Description: Search for archived pages, create Content Archive 2024 with
# file cabinet icon, move archived pages under it, duplicate Product Specs
# to create Legacy Product Specs with warning callout and additional sections
# =============================================================================
def _validate_agent_create_content_archive_system(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate content archive system creation with:
    - Main 'Content Archive 2024' page with file cabinet icon
    - Page marked as favorite
    - Archived pages found in search are children of this page
    - 'Legacy Product Specs' page exists as duplicate of Product Specs
    - Legacy Product Specs contains warning callout at top
    - Two additional sections: 'Deprecated Features' with bulleted lists and
      'Migration Notes' with numbered lists and code blocks
    
    Returns 1.0 only if ALL requirements are met, otherwise 0.0
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Find the main 'Content Archive 2024' page
    try:
        archive_pages = _get_pages_by_filter(backend, {"title": "Content Archive 2024"})
        if not archive_pages:
            errors.append("[X] Content Archive 2024 page not found")
        else:
            checks_passed.append("[C] Content Archive 2024 page found")
    
        archive_page = archive_pages[0]
        archive_id = archive_page.get("_id")
    
        # 2. Check for file cabinet icon
        icon = archive_page.get("icon")
        if not icon:
            errors.append("[X] Content Archive 2024 page does not have an icon")
        else:
            checks_passed.append("[C] Content Archive 2024 page has an icon")
    
        # Check if icon is file cabinet-related (could be emoji or custom)
        icon_value = icon.get("value", "").lower() if isinstance(icon, dict) else str(icon).lower()
        file_cabinet_emojis = ["🗄", "📁", "🗂", "cabinet", "file", "folder"]
        has_file_cabinet_icon = any(emoji in icon_value for emoji in file_cabinet_emojis)
    
        if not has_file_cabinet_icon:
            errors.append(f"[X] Content Archive 2024 page does not have a file cabinet icon (found: {icon_value})")
        else:
            checks_passed.append(f"[C] Content Archive 2024 page has a file cabinet icon (found: {icon_value})")
    
        # 3. Check if marked as favorite
        is_favorite = archive_page.get("isFavorite", False)
        if not is_favorite:
            errors.append("[X] Content Archive 2024 page is not marked as favorite")
        else:
            checks_passed.append("[C] Content Archive 2024 page is marked as favorite")
    
        # 4. Find archived pages that are children of Content Archive 2024
        child_pages = _get_pages_by_filter(backend, {"parentId": archive_id})
    
        # Count pages marked as archived that are now children of the archive page
        archived_children = [p for p in child_pages if p.get("isArchived", False)]
    
        # Note: We accept if there are ANY children, as some implementations may
        # move pages without preserving archive status or if no archived pages exist
        if len(child_pages) < 1:
            errors.append("[X] No pages found as children of Content Archive 2024 (archived pages should be moved here)")
        else:
            checks_passed.append("[C] pages found as children of Content Archive 2024 (archived pages should be moved here)")
    
        # 5. Find the 'Legacy Product Specs' page
        legacy_specs_pages = _get_pages_by_filter(backend, {"title": "Legacy Product Specs"})
        legacy_specs_page = None
        for p in legacy_specs_pages:
            if p.get("title", "").lower() == "legacy product specs":
                legacy_specs_page = p
                break
    
        if not legacy_specs_page:
            errors.append("[X] Legacy Product Specs page not found (should be duplicate of Product Specs)")
        else:
            checks_passed.append("[C] Legacy Product Specs page found (should be duplicate of Product Specs)")
    
        legacy_specs_id = legacy_specs_page.get("_id")
    
        # 6. Verify Product Specs still exists (not deleted, just duplicated)
        product_specs_pages = _get_pages_by_filter(backend, {"title": "Product Specs"})
        if not product_specs_pages:
            errors.append("[X] Product Specs page not found (should still exist after duplication)")
        else:
            checks_passed.append("[C] Product Specs page found (should still exist after duplication)")
    
        # 7. Get all blocks for Legacy Product Specs page
        legacy_specs_blocks = _get_blocks_by_filter(backend, {"pageId": legacy_specs_id})
    
        if len(legacy_specs_blocks) < 3:
            errors.append(f"[X] Legacy Product Specs needs sufficient blocks (callout, sections), found {len(legacy_specs_blocks)}")
        else:
            checks_passed.append(f"[C] Legacy Product Specs needs sufficient blocks (callout, sections), found {len(legacy_specs_blocks)}")
    
        # 8. Validate Legacy Product Specs contains a warning callout at top
        # The first block must be a callout with warning content
        first_block = legacy_specs_blocks[0]
        first_block_type = first_block.get("type", "")
        first_block_content = first_block.get("content", "").lower()
    
        if first_block_type != "callout":
            errors.append(f"[X] First block of Legacy Product Specs must be a warning callout, but found '{first_block_type}' instead")
        else:
            checks_passed.append(f"[C] First block of Legacy Product Specs must be a warning callout, but found '{first_block_type}' instead")
    
        if not ("archived" in first_block_content or "warning" in first_block_content or "legacy" in first_block_content):
            errors.append("[X] Warning callout at top of Legacy Product Specs does not contain expected warning text (archived/warning/legacy)")
        else:
            checks_passed.append("[C] Warning callout at top of Legacy Product Specs does contains expected warning text (archived/warning/legacy)")
    
        has_deprecated_features = False
        has_migration_notes = False
        has_bulleted_list = False
        has_numbered_list = False
        has_code_block = False
    
        for block in legacy_specs_blocks:
            block_type = block.get("type", "")
            block_content = block.get("content", "").lower()
        
            # Check for Deprecated Features heading
            if block_type in ["heading1", "heading2", "heading3"]:
                if "deprecated features" in block_content:
                    has_deprecated_features = True
                if "migration notes" in block_content:
                    has_migration_notes = True
        
            # Check for bulleted lists
            if block_type == "bulletedList":
                has_bulleted_list = True
        
            # Check for numbered lists
            if block_type == "numberedList":
                has_numbered_list = True
        
            # Check for code blocks
            if block_type == "code":
                has_code_block = True
    
        # 9. Validate 'Deprecated Features' section with bulleted lists
        if not has_deprecated_features:
            errors.append("[X] Legacy Product Specs does not contain 'Deprecated Features' section")
        else:
            checks_passed.append("[C] Legacy Product Specs does contains 'Deprecated Features' section")
    
        if not has_bulleted_list:
            errors.append("[X] Deprecated Features section does not contain bulleted lists")
        else:
            checks_passed.append("[C] Deprecated Features section does contains bulleted lists")
    
        # 10. Validate 'Migration Notes' section with numbered lists and code blocks
        if not has_migration_notes:
            errors.append("[X] Legacy Product Specs does not contain 'Migration Notes' section")
        else:
            checks_passed.append("[C] Legacy Product Specs does contains 'Migration Notes' section")
    
        if not has_numbered_list:
            errors.append("[X] Migration Notes section does not contain numbered lists")
        else:
            checks_passed.append("[C] Migration Notes section does contains numbered lists")
    
        if not has_code_block:
            errors.append("[X] Migration Notes section does not contain code blocks")
        else:
            checks_passed.append("[C] Migration Notes section does contains code blocks")
    
        # ALL requirements met!
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: add-guideline-callouts-sequence-v2
# Description: Navigate to Project Guidelines & Best Practices page, analyze
# existing callout pattern, insert sequence of 5 new callouts with specific
# colors/icons/text after TypeScript callout but before next Note callout,
# count total callouts and unique colors, add statistics section at end
# =============================================================================
def _validate_agent_add_guideline_callouts_sequence(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate guideline callouts sequence addition with:
    - 'Project Guidelines & Best Practices' page exists
    - 5 new callouts inserted in exact sequence after TypeScript callout
      but before next Note callout
    - Each callout has correct background color, icon, and exact text:
      1) Purple, 🎯, 'Objective: Achieve 90% code coverage in all modules'
      2) Pink, 🧪, 'Testing: Run integration tests before every PR merge'
      3) Brown, 📚, 'Documentation: Update README files for all API changes'
      4) Gray, ⚙️, 'Configuration: Use environment variables for all secrets'
      5) Blue, 🔗, 'Dependencies: Review and update packages monthly'
    - Heading2 '📊 Guideline Statistics' added at page end
    - Paragraph with exact format 'Total guidelines: [X] callouts across [Y] categories'
      where X is total callout count and Y is unique background color count
    
    Returns 1.0 only if ALL requirements are met, otherwise 0.0
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Find the 'Project Guidelines & Best Practices' page
    try:
        guidelines_pages = _get_pages_by_filter(backend, {"title": "Project Guidelines & Best Practices"})
        if not guidelines_pages:
            errors.append("[X] Project Guidelines & Best Practices page not found")
        else:
            checks_passed.append("[C] Project Guidelines & Best Practices page found")
    
        guidelines_page = guidelines_pages[0]
        guidelines_id = guidelines_page.get("_id")
    
        # 2. Get all blocks for the page
        page_blocks = _get_blocks_by_filter(backend, {"pageId": guidelines_id})
    
        if len(page_blocks) < 8:
            errors.append(f"[X] Project Guidelines & Best Practices needs sufficient blocks (5 new callouts + statistics section), found {len(page_blocks)}")
        else:
            checks_passed.append(f"[C] Project Guidelines & Best Practices needs sufficient blocks (5 new callouts + statistics section), found {len(page_blocks)}")
    
        # 3. Find key blocks: TypeScript callout, next Note callout, new callouts, statistics section
        typescript_callout_idx = -1
        next_note_callout_idx = -1
        statistics_heading_idx = -1
        statistics_paragraph_idx = -1
    
        # Expected new callouts with their properties
        # TODO: check if too strict
        expected_callouts = [
            {
                "background": "purple",
                "icon": "🎯",
                "text": "Objective: Achieve 90% code coverage in all modules"
            },
            {
                "background": "pink",
                "icon": "🧪",
                "text": "Testing: Run integration tests before every PR merge"
            },
            {
                "background": "brown",
                "icon": "📚",
                "text": "Documentation: Update README files for all API changes"
            },
            {
                "background": "gray",
                "icon": "⚙️",
                "text": "Configuration: Use environment variables for all secrets"
            },
            {
                "background": "blue",
                "icon": "🔗",
                "text": "Dependencies: Review and update packages monthly"
            }
        ]
    
        found_new_callouts = []
    
        # Parse blocks to find relevant elements
        for idx, block in enumerate(page_blocks):
            block_type = block.get("type", "")
            block_content = block.get("content", "")
            block_properties = block.get("properties", {})
        
            # Find FIRST TypeScript strict mode callout (only set once)
            if block_type == "callout" and "typescript strict mode" in block_content.lower():
                if typescript_callout_idx == -1:  # Only record the first one
                    typescript_callout_idx = idx
        
            # Find next Note callout (after TypeScript callout)
            if block_type == "callout" and typescript_callout_idx != -1 and idx > typescript_callout_idx:
                if "note:" in block_content.lower():
                    if next_note_callout_idx == -1:  # Only record the first one
                        next_note_callout_idx = idx
        
            # Find statistics heading
            if block_type == "heading2" and "guideline statistics" in block_content.lower():
                statistics_heading_idx = idx
        
            # Find statistics paragraph
            if block_type == "paragraph" and "total guidelines:" in block_content.lower():
                statistics_paragraph_idx = idx
        
            # Check for new callouts
            if block_type == "callout":
                background_color = ""
                icon_value = ""
            
                if isinstance(block_properties, dict):
                    background_color = block_properties.get("backgroundColor", "").lower()
                    icon_prop = block_properties.get("icon", "")
                    if isinstance(icon_prop, dict):
                        icon_value = icon_prop.get("value", "")
                    else:
                        icon_value = str(icon_prop)
            
                # Check if this callout matches any of our expected new callouts
                for expected in expected_callouts:
                    if (expected["background"] in background_color and
                        expected["icon"] in icon_value and
                        expected["text"].lower() in block_content.lower()):
                        found_new_callouts.append({
                            "idx": idx,
                            "expected": expected,
                            "background": background_color,
                            "icon": icon_value,
                            "text": block_content
                        })
                        break
    
        # 4. Validate TypeScript callout was found
        if typescript_callout_idx == -1:
            errors.append("[X] TypeScript strict mode callout not found")
        else:
            checks_passed.append("[C] TypeScript strict mode callout found")
    
        # 5. Validate next Note callout was found
        if next_note_callout_idx == -1:
            errors.append("[X] Next 'Note:' callout after TypeScript callout not found")
        else:
            checks_passed.append("[C] Next 'Note:' callout after TypeScript callout found")
    
        # 6. Validate all 5 new callouts were found
        if len(found_new_callouts) != 5:
            missing = [exp["text"] for exp in expected_callouts if not any(fc["expected"]["text"] == exp["text"] for fc in found_new_callouts)]
            errors.append(f"[X] Expected 5 new callouts, found {len(found_new_callouts)}. Missing: {missing[:2] if missing else 'unknown'}")
        else:
            checks_passed.append(f"[C] Found 5 new callouts as expected")
    
        # 7. Validate callouts are positioned correctly (between TypeScript and Note)
        # Currently failing here
        for callout_info in found_new_callouts:
            callout_idx = callout_info["idx"]
            if not (typescript_callout_idx < callout_idx < next_note_callout_idx):
                errors.append(f"[X] Callout '{callout_info['expected']['text'][:50]}...' not positioned between TypeScript callout (idx {typescript_callout_idx}) and Note callout (idx {next_note_callout_idx}), found at idx {callout_idx}")
            else:
                checks_passed.append(f"[C] Callout '{callout_info['expected']['text'][:50]}...' positioned between TypeScript callout (idx {typescript_callout_idx}) and Note callout (idx {next_note_callout_idx}), found at idx {callout_idx}")
    
        # 8. Validate callouts are in correct sequence
        callout_indices = sorted([c["idx"] for c in found_new_callouts])
        for i, idx in enumerate(callout_indices):
            # Find which callout is at this index
            callout_at_idx = next(c for c in found_new_callouts if c["idx"] == idx)
            expected_at_position = expected_callouts[i]
        
            if callout_at_idx["expected"]["text"] != expected_at_position["text"]:
                errors.append(f"[X] Callouts not in correct sequence. Position {i+1} should be '{expected_at_position['text'][:50]}...' but found '{callout_at_idx['expected']['text'][:50]}...'")
            else:
                checks_passed.append(f"[C] Callouts in correct sequence. Position {i+1} should be '{expected_at_position['text'][:50]}...' but found '{callout_at_idx['expected']['text'][:50]}...'")
    
        # 9. Count total callouts and unique background colors
        total_callouts = sum(1 for b in page_blocks if b.get("type") == "callout")
        unique_colors = set()
        for block in page_blocks:
            if block.get("type") == "callout":
                props = block.get("properties", {})
                if isinstance(props, dict):
                    bg_color = props.get("backgroundColor", "")
                    if bg_color:
                        unique_colors.add(bg_color.lower())
    
        unique_color_count = len(unique_colors)
    
        # 10. Validate statistics heading at end
        if statistics_heading_idx == -1:
            errors.append("[X] Guideline Statistics heading2 not found at page end")
        else:
            checks_passed.append("[C] Guideline Statistics heading2 found at page end")
    
        # Statistics should be near the end (after all callouts)
        if statistics_heading_idx < next_note_callout_idx:
            errors.append(f"[X] Guideline Statistics heading should be at page end, found at idx {statistics_heading_idx} but Note callout is at {next_note_callout_idx}")
        else:
            checks_passed.append(f"[C] Guideline Statistics heading should be at page end, found at idx {statistics_heading_idx} but Note callout is at {next_note_callout_idx}")
    
        # 11. Validate statistics paragraph
        if statistics_paragraph_idx == -1:
            errors.append("[X] Statistics paragraph with 'Total guidelines:' not found")
        else:
            checks_passed.append("[C] Statistics paragraph with 'Total guidelines:' found")
    
        # Paragraph should be after statistics heading
        if statistics_paragraph_idx <= statistics_heading_idx:
            errors.append(f"[X] Statistics paragraph should appear after heading (heading at {statistics_heading_idx}, paragraph at {statistics_paragraph_idx})")
        else:
            checks_passed.append(f"[C] Statistics paragraph should appear after heading (heading at {statistics_heading_idx}, paragraph at {statistics_paragraph_idx})")
    
        # 12. Validate paragraph format and counts
        stats_paragraph = page_blocks[statistics_paragraph_idx]
        stats_content = stats_paragraph.get("content", "").lower()
    
        # Check if paragraph contains the correct counts
        if f"{total_callouts}" not in stats_content:
            errors.append(f"[X] Statistics paragraph should mention total callout count {total_callouts}, but content is: '{stats_content}'")
        else:
            checks_passed.append(f"[C] Statistics paragraph should mention total callout count {total_callouts}, but content is: '{stats_content}'")
    
        if f"{unique_color_count}" not in stats_content:
            errors.append(f"[X] Statistics paragraph should mention unique color count {unique_color_count}, but content is: '{stats_content}'")
        else:
            checks_passed.append(f"[C] Statistics paragraph should mention unique color count {unique_color_count}, but content is: '{stats_content}'")
    
        if "callouts" not in stats_content or "categories" not in stats_content:
            errors.append("[X] Statistics paragraph should follow format 'Total guidelines: [X] callouts across [Y] categories'")
        else:
            checks_passed.append("[C] Statistics paragraph should follow format 'Total guidelines: [X] callouts across [Y] categories'")
    
        # ALL requirements met!
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: add-java-section-to-code-examples-v2
# Description: Navigate to Code Examples Repository page and add a Java Examples
# section with specific positioning after Go code block and before Rust heading.
# Add Java code block, description, count all code blocks, and add summary callout
# at top.
# =============================================================================
def _validate_agent_add_java_section_to_code_examples(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate Java section addition to Code Examples Repository with:
    - 'Code Examples Repository' page exists
    - 'Java Examples' heading_2 appears AFTER 'Go Examples' code block
      and BEFORE 'Rust Examples' heading
    - Java code block with language='java' and exact specified content
    - Java description paragraph matching format of other sections
    - Yellow callout at very top (after main heading) with '📊' icon
    - Callout contains 'This repository contains [X] code examples across [Y] programming languages.'
    - Correct counts: 8 code examples, 8 languages
    
    Returns 1.0 only if ALL requirements are met, otherwise 0.0
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Find the 'Code Examples Repository' page
    try:
        code_examples_pages = _get_pages_by_filter(backend, {"title": "Code Examples Repository"})
        if not code_examples_pages:
            errors.append("[X] Code Examples Repository page not found")
        else:
            checks_passed.append("[C] Code Examples Repository page found")
    
        code_examples_page = code_examples_pages[0]
        code_examples_id = code_examples_page.get("_id")
    
        # 2. Get all blocks for the Code Examples Repository page
        page_blocks = _get_blocks_by_filter(backend, {"pageId": code_examples_id})
    
        if len(page_blocks) < 5:
            errors.append(f"[X] Code Examples Repository needs sufficient blocks for Java section and callout, found {len(page_blocks)}")
        else:
            checks_passed.append(f"[C] Code Examples Repository needs sufficient blocks for Java section and callout, found {len(page_blocks)}")
    
        # 3. Find key blocks: Go code block, Rust heading, Java heading, Java code, Java description, yellow callout
        go_code_block_idx = -1
        rust_heading_idx = -1
        java_heading_idx = -1
        java_code_block_idx = -1
        java_description_idx = -1
        yellow_callout_idx = -1
    
        expected_java_code = "public class HelloWorld { public static void main(String[] args) { System.out.println(\"Hello, Notion!\"); List<String> items = Arrays.asList(\"Code\", \"Test\", \"Deploy\"); items.forEach(System.out::println); } }"
    
        for idx, block in enumerate(page_blocks):
            block_type = block.get("type", "")
            block_content = block.get("content", "")
            block_properties = block.get("properties", {})
        
            # Find Go Examples code block
            if block_type == "code":
                if isinstance(block_properties, dict) and block_properties.get("language") == "go":
                    go_code_block_idx = idx
        
            # Find Rust Examples heading
            if block_type == "heading2" and "rust examples" in block_content.lower():
                rust_heading_idx = idx
        
            # Find Java Examples heading
            if block_type == "heading2" and "java examples" in block_content.lower():
                java_heading_idx = idx
        
            # Find Java code block
            if block_type == "code":
                if isinstance(block_properties, dict) and block_properties.get("language") == "java":
                    # Check content matches (normalize whitespace)
                    if block_content.strip() == expected_java_code.strip():
                        java_code_block_idx = idx
        
            # Find Java description paragraph
            if block_type == "paragraph" and "common java pattern" in block_content.lower():
                java_description_idx = idx
        
            # Find yellow callout with chart emoji at top
            if block_type == "callout":
                background_color = block_properties.get("backgroundColor", "") if isinstance(block_properties, dict) else ""
                icon_prop = block_properties.get("icon", "") if isinstance(block_properties, dict) else ""
                icon_value = icon_prop.get("value", "") if isinstance(icon_prop, dict) else str(icon_prop)
            
                if ("yellow" in background_color.lower() and 
                    "📊" in icon_value and 
                    "this repository contains" in block_content.lower()):
                    yellow_callout_idx = idx
    
        # 4. Validate Go Examples code block exists
        if go_code_block_idx == -1:
            errors.append("[X] Go Examples code block not found")
        else:
            checks_passed.append("[C] Go Examples code block found")
    
        # 5. Validate Rust Examples heading exists
        if rust_heading_idx == -1:
            errors.append("[X] Rust Examples heading not found")
        else:
            checks_passed.append("[C] Rust Examples heading found")
    
        # 6. Validate Java Examples heading exists
        if java_heading_idx == -1:
            errors.append("[X] Java Examples heading_2 not found")
        else:
            checks_passed.append("[C] Java Examples heading_2 found")
    
        # 7. Validate Java heading is positioned correctly (after Go code, before Rust heading)
        if not (go_code_block_idx < java_heading_idx < rust_heading_idx):
            errors.append(f"[X] Java Examples heading not positioned correctly. Expected: Go code block (idx {go_code_block_idx}) < Java heading (idx {java_heading_idx}) < Rust heading (idx {rust_heading_idx})")
        else:
            checks_passed.append(f"[C] Java Examples heading positioned correctly. Expected: Go code block (idx {go_code_block_idx}) < Java heading (idx {java_heading_idx}) < Rust heading (idx {rust_heading_idx})")
    
        # 8. Validate Java code block exists with correct content and language
        if java_code_block_idx == -1:
            errors.append("[X] Java code block with correct language property and exact content not found")
        else:
            checks_passed.append("[C] Java code block with correct language property and exact content found")
    
        # Code block should be after Java heading
        if java_code_block_idx <= java_heading_idx:
            errors.append(f"[X] Java code block should appear after Java heading (heading at {java_heading_idx}, code at {java_code_block_idx})")
        else:
            checks_passed.append(f"[C] Java code block should appear after Java heading (heading at {java_heading_idx}, code at {java_code_block_idx})")
    
        # 9. Validate Java description paragraph
        if java_description_idx == -1:
            errors.append("[X] Java description paragraph ('Common java pattern for production code.') not found")
        else:
            checks_passed.append("[C] Java description paragraph ('Common java pattern for production code.') found")
    
        # Description should be after code block
        if java_description_idx <= java_code_block_idx:
            errors.append(f"[X] Java description paragraph should appear after code block (code at {java_code_block_idx}, description at {java_description_idx})")
        else:
            checks_passed.append(f"[C] Java description paragraph should appear after code block (code at {java_code_block_idx}, description at {java_description_idx})")
    
        # 10. Count all code blocks on the page
        total_code_blocks = sum(1 for b in page_blocks if b.get("type") == "code")
    
        # 11. Count unique programming languages
        unique_languages = set()
        for block in page_blocks:
            if block.get("type") == "code":
                props = block.get("properties", {})
                if isinstance(props, dict):
                    lang = props.get("language", "")
                    if lang:
                        unique_languages.add(lang.lower())
    
        unique_language_count = len(unique_languages)
    
        # 12. Validate yellow callout at top with correct icon
        if yellow_callout_idx == -1:
            errors.append("[X] Yellow callout with '📊' icon not found at top of page")
        else:
            checks_passed.append("[C] Yellow callout with '📊' icon found at top of page")
    
        # Callout should be near the top (after main heading)
        # Find the first heading1 (main title)
        main_heading_idx = -1
        for idx, block in enumerate(page_blocks):
            if block.get("type") == "heading1":
                main_heading_idx = idx
                break
    
        if main_heading_idx != -1:
            # Callout should be after main heading but before the first language section
            if yellow_callout_idx <= main_heading_idx:
                errors.append(f"[X] Yellow callout should appear after main heading (heading at {main_heading_idx}, callout at {yellow_callout_idx})")
            else:
                checks_passed.append(f"[C] Yellow callout should appear after main heading (heading at {main_heading_idx}, callout at {yellow_callout_idx})")
    
        # 13. Validate callout text contains correct counts
        callout_block = page_blocks[yellow_callout_idx]
        callout_content = callout_block.get("content", "")
    
        # Expected: 8 code examples, 8 programming languages
        expected_code_count = 8
        expected_lang_count = 8
    
        if f"{expected_code_count}" not in callout_content:
            errors.append(f"[X] Yellow callout should mention {expected_code_count} code examples, but found: {total_code_blocks} (content: '{callout_content[:100]}...')")
        else:
            checks_passed.append(f"[C] Yellow callout should mention {expected_code_count} code examples, but found: {total_code_blocks} (content: '{callout_content[:100]}...')")
    
        if f"{expected_lang_count}" not in callout_content:
            errors.append(f"[X] Yellow callout should mention {expected_lang_count} programming languages, but found: {unique_language_count} (content: '{callout_content[:100]}...')")
        else:
            checks_passed.append(f"[C] Yellow callout should mention {expected_lang_count} programming languages, but found: {unique_language_count} (content: '{callout_content[:100]}...')")
    
        if "code examples" not in callout_content.lower() or "programming languages" not in callout_content.lower():
            errors.append("[X] Yellow callout should contain 'code examples' and 'programming languages'")
        else:
            checks_passed.append("[C] Yellow callout should contain 'code examples' and 'programming languages'")
    
        # Verify actual counts match expected
        if total_code_blocks != expected_code_count:
            errors.append(f"[X] Expected {expected_code_count} code blocks on page, found {total_code_blocks}")
        else:
            checks_passed.append(f"[C] Expected {expected_code_count} code blocks on page, found {total_code_blocks}")
    
        if unique_language_count != expected_lang_count:
            errors.append(f"[X] Expected {expected_lang_count} unique programming languages, found {unique_language_count}")
        else:
            checks_passed.append(f"[C] Expected {expected_lang_count} unique programming languages, found {unique_language_count}")
    
        # ALL requirements met!
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: create-project-metrics-dashboard-v2
# Description: Create a comprehensive Project Metrics Dashboard page that fetches
# and analyzes to-do blocks from Project Roadmap sub-pages (Q1 and Q2 Goals),
# calculates completion statistics, and displays structured metrics
# =============================================================================
def _validate_agent_create_project_metrics_dashboard(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate Project Metrics Dashboard creation with:
    - New page 'Project Metrics Dashboard' with '📊' icon as child of 'Project Documentation'
    - Heading hierarchy: heading1 → heading2 → heading3
    - Callout with Blue background and '📈' icon
    - Accurate todo counts from Project Roadmap sub-pages (Q1 Goals, Q2 Goals)
    - Separate completed/in-progress counts and correct percentage calculations for each quarter
    - Quote block at the end (TODO: should check for italic formatting in future)
    
    Returns 1.0 only if ALL requirements are met, otherwise 0.0
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Find the 'Project Metrics Dashboard' page
    try:
        dashboard_page = _find_page_by_title(final_state_backend, "Project Metrics Dashboard")
        if not dashboard_page:
            errors.append("[X] Project Metrics Dashboard page not found")
        else:
            checks_passed.append("[C] Project Metrics Dashboard page found")
    
        dashboard_id = dashboard_page.get("_id")
    
        # 2. Check for '📊' icon
        icon = dashboard_page.get("icon")
        if not icon:
            errors.append("[X] Project Metrics Dashboard page does not have an icon")
        else:
            checks_passed.append("[C] Project Metrics Dashboard page has an icon")
    
        # Check if icon is chart/dashboard-related
        icon_value = icon.get("value", "").lower() if isinstance(icon, dict) else str(icon).lower()
        dashboard_emojis = ["📊", "📈", "📉", "chart", "dashboard", "bar"]
        has_dashboard_icon = any(emoji in icon_value for emoji in dashboard_emojis)
    
        if not has_dashboard_icon:
            errors.append(f"[X] Project Metrics Dashboard page does not have a dashboard icon (found: {icon_value})")
        else:
            checks_passed.append(f"[C] Project Metrics Dashboard page has a dashboard icon (found: {icon_value})")
    
        # 3. Verify it's a child of 'Project Documentation'
        project_doc_page = _find_page_by_title(final_state_backend, "Project Documentation")
        if not project_doc_page:
            errors.append("[X] Project Documentation page not found")
        else:
            checks_passed.append("[C] Project Documentation page found")
    
        is_child = _check_page_is_child_of(project_doc_page, dashboard_page)
        if not is_child:
            errors.append("[X] Project Metrics Dashboard is not a child of 'Project Documentation'")
        else:
            checks_passed.append("[C] Project Metrics Dashboard is a child of 'Project Documentation'")
    
        # 4. Find Project Roadmap and its sub-pages (Q1 Goals, Q2 Goals)
        project_roadmap = _find_page_by_title(final_state_backend, "Project Roadmap")
        if not project_roadmap:
            errors.append("[X] Project Roadmap page not found")
        else:
            checks_passed.append("[C] Project Roadmap page found")
    
        roadmap_id = project_roadmap.get("_id")
    
        q1_goals_page = _find_child_by_title(final_state_backend, project_roadmap, "Q1 Goals")
        q2_goals_page = _find_child_by_title(final_state_backend, project_roadmap, "Q2 Goals")
    
        if not q1_goals_page:
            errors.append("[X] Q1 Goals page not found as child of Project Roadmap")
        else:
            checks_passed.append("[C] Q1 Goals page found as child of Project Roadmap")
    
        if not q2_goals_page:
            errors.append("[X] Q2 Goals page not found as child of Project Roadmap")
        else:
            checks_passed.append("[C] Q2 Goals page found as child of Project Roadmap")
    
        # 5. Count todos from Q1 and Q2 pages - using query-level filtering
        q1_todos = _get_todo_blocks(final_state_backend, q1_goals_page.get("_id"))
        q2_todos = _get_todo_blocks(final_state_backend, q2_goals_page.get("_id"))
    
        # Count Q1 todos (already filtered)
        q1_completed = sum(1 for t in q1_todos if t.get("properties", {}).get("checked", False))
        q1_in_progress = len(q1_todos) - q1_completed
        q1_completion_rate = round((q1_completed / len(q1_todos) * 100) if len(q1_todos) > 0 else 0)
    
        # Count Q2 todos (already filtered above)
        q2_completed = sum(1 for t in q2_todos if t.get("properties", {}).get("checked", False))
        q2_in_progress = len(q2_todos) - q2_completed
        q2_completion_rate = round((q2_completed / len(q2_todos) * 100) if len(q2_todos) > 0 else 0)
    
        total_todos = len(q1_todos) + len(q2_todos)
    
        # 6. Get all blocks for the dashboard page
        dashboard_blocks = _get_blocks_for_page(final_state_backend, dashboard_id)
    
        if len(dashboard_blocks) < 7:
            errors.append(f"[X] Project Metrics Dashboard needs at least 7 blocks (heading1, callout, heading2, paragraph, heading3s, bulleted lists, divider, quote), found {len(dashboard_blocks)}")
        else:
            checks_passed.append(f"[C] Project Metrics Dashboard needs at least 7 blocks (heading1, callout, heading2, paragraph, heading3s, bulleted lists, divider, quote), found {len(dashboard_blocks)}")
    
        # 7. Validate block structure and content
        has_main_heading1 = False
        has_blue_callout = False
        has_goals_overview_heading2 = False
        has_total_paragraph = False
        has_q1_heading3 = False
        has_q2_heading3 = False
        has_divider = False
        has_quote = False
        # TODO: Re-enable italic check for quote block when formatting is ready
        # quote_has_italic = False
    
        total_paragraph_correct = False
        q1_stats_correct = False
        q2_stats_correct = False
    
        q1_bulleted_count = 0
        q2_bulleted_count = 0
    
        found_q1_section = False
        found_q2_section = False
    
        for idx, block in enumerate(dashboard_blocks):
            block_type = block.get("type", "")
            block_content = block.get("content", "")
            block_properties = block.get("properties", {})
        
            # Check for main heading1
            if block_type == "heading1" and "project metrics dashboard" in block_content.lower():
                has_main_heading1 = True
        
            # Check for blue callout with chart icon
            if block_type == "callout":
                background_color = block_properties.get("backgroundColor", "").lower() if isinstance(block_properties, dict) else ""
                icon_prop = block_properties.get("icon", "") if isinstance(block_properties, dict) else ""
                icon_val = icon_prop.get("value", "") if isinstance(icon_prop, dict) else str(icon_prop)
            
                if ("blue" in background_color and 
                    "📈" in icon_val and 
                    "real-time project health metrics" in block_content.lower()):
                    has_blue_callout = True
        
            # Check for Goals Overview heading2
            if block_type == "heading2" and "goals overview" in block_content.lower():
                has_goals_overview_heading2 = True
        
            # Check for total paragraph
            if block_type == "paragraph" and "total project goals across all quarters" in block_content.lower():
                has_total_paragraph = True
                # Check if it has the correct count
                if str(total_todos) in block_content:
                    total_paragraph_correct = True
        
            # Check for Q1 heading3
            if block_type == "heading3" and "q1 2024 progress" in block_content.lower():
                has_q1_heading3 = True
                found_q1_section = True
        
            # Check for Q2 heading3
            if block_type == "heading3" and "q2 2024 progress" in block_content.lower():
                has_q2_heading3 = True
                found_q2_section = True
                found_q1_section = False  # Mark end of Q1 section
        
            # Count bulleted lists in Q1 section
            if block_type == "bulletedList" and found_q1_section and not found_q2_section:
                q1_bulleted_count += 1
                # Check if content has correct stats
                content_lower = block_content.lower()
                if f"completed: {q1_completed}" in content_lower:
                    q1_stats_correct = True
                elif f"in progress: {q1_in_progress}" in content_lower:
                    pass  # Expected
                elif f"completion rate: {q1_completion_rate}%" in content_lower:
                    pass  # Expected
        
            # Count bulleted lists in Q2 section
            if block_type == "bulletedList" and found_q2_section:
                q2_bulleted_count += 1
                # Check if content has correct stats
                content_lower = block_content.lower()
                if f"completed: {q2_completed}" in content_lower:
                    q2_stats_correct = True
                elif f"in progress: {q2_in_progress}" in content_lower:
                    pass  # Expected
                elif f"completion rate: {q2_completion_rate}%" in content_lower:
                    pass  # Expected
        
            # Check for divider
            if block_type == "divider":
                has_divider = True
        
            # Check for quote block
            # TODO: Re-enable italic formatting check when ready - should verify italic formatting
            if block_type == "quote":
                if "data aggregated from project roadmap" in block_content.lower():
                    has_quote = True
                    # RELAXED: Italic formatting check temporarily disabled
                    # content_stripped = block_content.strip()
                    # if content_stripped.startswith("*") and content_stripped.endswith("*"):
                    #     quote_has_italic = True
    
        # 8. Validate all required elements
        if not has_main_heading1:
            errors.append("[X] Dashboard does not contain main heading1 '📊 Project Metrics Dashboard'")
        else:
            checks_passed.append("[C] Dashboard does contains main heading1 '📊 Project Metrics Dashboard'")
    
        if not has_blue_callout:
            errors.append("[X] Dashboard does not contain Blue callout with '📈' icon and correct text")
        else:
            checks_passed.append("[C] Dashboard does contains Blue callout with '📈' icon and correct text")
    
        if not has_goals_overview_heading2:
            errors.append("[X] Dashboard does not contain heading2 '🎯 Goals Overview'")
        else:
            checks_passed.append("[C] Dashboard does contains heading2 '🎯 Goals Overview'")
    
        if not has_total_paragraph:
            errors.append("[X] Dashboard does not contain paragraph with 'Total project goals across all quarters'")
        else:
            checks_passed.append("[C] Dashboard does contains paragraph with 'Total project goals across all quarters'")
    
        if not total_paragraph_correct:
            errors.append(f"[X] Total paragraph does not contain correct count. Expected {total_todos} todos")
        else:
            checks_passed.append(f"[C] Total paragraph does contains correct count. Expected {total_todos} todos")
    
        if not has_q1_heading3:
            errors.append("[X] Dashboard does not contain heading3 '📅 Q1 2024 Progress'")
        else:
            checks_passed.append("[C] Dashboard does contains heading3 '📅 Q1 2024 Progress'")
    
        if q1_bulleted_count < 3:
            errors.append(f"[X] Q1 section needs 3 bulleted list items (Completed, In Progress, Completion Rate), found {q1_bulleted_count}")
        else:
            checks_passed.append(f"[C] Q1 section needs 3 bulleted list items (Completed, In Progress, Completion Rate), found {q1_bulleted_count}")
    
        if not q1_stats_correct:
            errors.append(f"[X] Q1 statistics are incorrect. Expected Completed: {q1_completed}, In Progress: {q1_in_progress}, Completion Rate: {q1_completion_rate}%")
        else:
            checks_passed.append(f"[C] Q1 statistics are incorrect. Expected Completed: {q1_completed}, In Progress: {q1_in_progress}, Completion Rate: {q1_completion_rate}%")
    
        if not has_q2_heading3:
            errors.append("[X] Dashboard does not contain heading3 '📅 Q2 2024 Progress'")
        else:
            checks_passed.append("[C] Dashboard does contains heading3 '📅 Q2 2024 Progress'")
    
        if q2_bulleted_count < 3:
            errors.append(f"[X] Q2 section needs 3 bulleted list items (Completed, In Progress, Completion Rate), found {q2_bulleted_count}")
        else:
            checks_passed.append(f"[C] Q2 section needs 3 bulleted list items (Completed, In Progress, Completion Rate), found {q2_bulleted_count}")
    
        if not q2_stats_correct:
            errors.append(f"[X] Q2 statistics are incorrect. Expected Completed: {q2_completed}, In Progress: {q2_in_progress}, Completion Rate: {q2_completion_rate}%")
        else:
            checks_passed.append(f"[C] Q2 statistics are incorrect. Expected Completed: {q2_completed}, In Progress: {q2_in_progress}, Completion Rate: {q2_completion_rate}%")
    
        if not has_divider:
            errors.append("[X] Dashboard does not contain a divider block")
        else:
            checks_passed.append("[C] Dashboard does contains a divider block")
    
        if not has_quote:
            errors.append("[X] Dashboard does not contain quote block with 'Data aggregated from Project Roadmap sub-pages'")
        else:
            checks_passed.append("[C] Dashboard does contains quote block with 'Data aggregated from Project Roadmap sub-pages'")
    
        # TODO: Re-enable italic check for quote block when formatting is ready
        # if not quote_has_italic:
        #     return 0.0, "Quote block does not have italic formatting"
    
        # ALL requirements met!
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: add-followup-tasks-to-sprint-planning-v2
# Description: Navigate to Sprint Planning - Jan 15 page, locate Action Items 
# section, and insert new follow-up tasks section with 5 specific to-do items 
# and a divider after the existing to-dos.
# =============================================================================
def _validate_agent_add_followup_tasks_to_sprint_planning(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate addition of follow-up tasks to Sprint Planning - Jan 15 page with:
    - 'Sprint Planning - Jan 15' page exists
    - New 'Follow-up Tasks - Jan 22' heading_2 appears immediately after 
      block-3-1-12 (the last existing to-do in Action Items section)
    - Exactly 5 new unchecked to-do blocks with exact text including emojis:
      1. '📋 Review sprint retrospective feedback'
      2. '🔍 Analyze velocity metrics from current sprint'
      3. '💬 Schedule 1:1s with team members'
      4. '🎯 Update roadmap based on completed items'
      5. '⚡ Prepare demo for stakeholder review'
    - Divider block placed after the last new to-do
    
    Returns 1.0 only if ALL requirements are met, otherwise 0.0
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Find the 'Sprint Planning - Jan 15' page
    try:
        sprint_pages = _get_pages_by_filter(backend, {"title": "Sprint Planning - Jan 15"})
        if not sprint_pages:
            errors.append("[X] Sprint Planning - Jan 15 page not found")
        else:
            checks_passed.append("[C] Sprint Planning - Jan 15 page found")
    
        sprint_page = sprint_pages[0]
        sprint_id = sprint_page.get("_id")
    
        # 2. Get all blocks for the Sprint Planning page
        page_blocks = _get_blocks_by_filter(backend, {"pageId": sprint_id})
    
        if len(page_blocks) < 5:
            errors.append(f"[X] Sprint Planning page needs sufficient blocks for new follow-up tasks section, found {len(page_blocks)}")
        else:
            checks_passed.append(f"[C] Sprint Planning page needs sufficient blocks for new follow-up tasks section, found {len(page_blocks)}")
    
        # 3. Find key blocks: Action Items heading, block-3-1-12 (last existing todo),
        #    new Follow-up Tasks heading, 5 new todos, and divider
        action_items_heading_idx = -1
        last_existing_todo_idx = -1  # block-3-1-12
        followup_heading_idx = -1
        followup_todos_indices = []
        divider_after_todos_idx = -1
    
        # Expected to-do texts in exact order
        expected_todos = [
            "📋 Review sprint retrospective feedback",
            "🔍 Analyze velocity metrics from current sprint",
            "💬 Schedule 1:1s with team members",
            "🎯 Update roadmap based on completed items",
            "⚡ Prepare demo for stakeholder review"
        ]
    
        found_todos = []
    
        for idx, block in enumerate(page_blocks):
            block_type = block.get("type", "")
            block_content = block.get("content", "")
            block_id = block.get("_id", "")
            block_properties = block.get("properties", {})
        
            # Find Action Items heading (heading1 or heading2)
            if block_type in ["heading1", "heading2"] and "action items" in block_content.lower():
                action_items_heading_idx = idx
        
            # Find block-3-1-12 (last existing to-do)
            # We'll identify this by looking for the last todo before the new heading
            if block_id == "block-3-1-12":
                last_existing_todo_idx = idx
        
            # Find Follow-up Tasks heading
            if block_type == "heading2" and "follow-up tasks - jan 22" in block_content.lower():
                followup_heading_idx = idx
        
            # Find new to-do blocks with exact text
            if block_type == "todo":
                for expected_todo in expected_todos:
                    if block_content.strip() == expected_todo.strip():
                        # Check if it's unchecked
                        is_checked = block_properties.get("checked", False) if isinstance(block_properties, dict) else False
                        found_todos.append({
                            "idx": idx,
                            "text": block_content.strip(),
                            "checked": is_checked,
                            "expected": expected_todo
                        })
                        break
        
            # Find divider blocks
            if block_type == "divider":
                # We'll check later if this divider is in the right position
                if followup_heading_idx != -1 and idx > followup_heading_idx:
                    divider_after_todos_idx = idx
    
        # 4. Validate Action Items heading was found
        if action_items_heading_idx == -1:
            errors.append("[X] Action Items section not found")
        else:
            checks_passed.append("[C] Action Items section found")
    
        # 5. Validate Follow-up Tasks heading was found
        if followup_heading_idx == -1:
            errors.append("[X] Follow-up Tasks - Jan 22 heading not found")
        else:
            checks_passed.append("[C] Follow-up Tasks - Jan 22 heading found")
    
        # 6. If we found block-3-1-12, validate heading appears after it
        # Otherwise, just check it appears after Action Items heading
        if last_existing_todo_idx != -1:
            if followup_heading_idx <= last_existing_todo_idx:
                errors.append(f"[X] Follow-up Tasks heading should appear after block-3-1-12 (idx {last_existing_todo_idx}), but found at idx {followup_heading_idx}")
            else:
                checks_passed.append(f"[C] Follow-up Tasks heading should appear after block-3-1-12 (idx {last_existing_todo_idx}), but found at idx {followup_heading_idx}")
        else:
            # If we can't find block-3-1-12 by ID, check positioning relative to Action Items
            if followup_heading_idx <= action_items_heading_idx:
                errors.append(f"[X] Follow-up Tasks heading should appear after Action Items section (idx {action_items_heading_idx}), but found at idx {followup_heading_idx}")
            else:
                checks_passed.append(f"[C] Follow-up Tasks heading should appear after Action Items section (idx {action_items_heading_idx}), but found at idx {followup_heading_idx}")
    
        # 7. Validate all 5 to-dos were found
        if len(found_todos) != 5:
            missing = [exp for exp in expected_todos if not any(ft["expected"] == exp for ft in found_todos)]
            errors.append(f"[X] Expected 5 new to-do blocks, found {len(found_todos)}. Missing: {missing[:2] if missing else 'unknown'}")
        else:
            checks_passed.append(f"[C] Found 5 new to-do blocks as expected")
    
        # 8. Validate all to-dos are unchecked
        checked_todos = [ft for ft in found_todos if ft["checked"]]
        if checked_todos:
            errors.append(f"[X] All to-do blocks should be unchecked, but {len(checked_todos)} are checked")
        else:
            checks_passed.append(f"[C] All to-do blocks should be unchecked, but {len(checked_todos)} are checked")
    
        # 9. Validate to-dos appear in correct sequence and after the Follow-up heading
        todo_indices = [ft["idx"] for ft in found_todos]
        todo_indices.sort()
    
        # Check all todos appear after the heading
        for todo_idx in todo_indices:
            if todo_idx <= followup_heading_idx:
                errors.append(f"[X] To-do blocks should appear after Follow-up Tasks heading (idx {followup_heading_idx}), found to-do at idx {todo_idx}")
            else:
                checks_passed.append(f"[C] To-do blocks should appear after Follow-up Tasks heading (idx {followup_heading_idx}), found to-do at idx {todo_idx}")
    
        # Check todos are in correct sequence
        for i, idx in enumerate(todo_indices):
            todo_at_idx = next(ft for ft in found_todos if ft["idx"] == idx)
            expected_at_position = expected_todos[i]
        
            if todo_at_idx["expected"] != expected_at_position:
                errors.append(f"[X] To-dos not in correct sequence. Position {i+1} should be '{expected_at_position}' but found '{todo_at_idx['text']}'")
            else:
                checks_passed.append(f"[C] To-dos in correct sequence. Position {i+1} should be '{expected_at_position}' but found '{todo_at_idx['text']}'")
    
        # 10. Validate divider block appears after the last to-do
        if divider_after_todos_idx == -1:
            errors.append("[X] Divider block not found after Follow-up Tasks section")
        else:
            checks_passed.append("[C] Divider block found after Follow-up Tasks section")
    
        last_todo_idx = max(todo_indices)
        if divider_after_todos_idx <= last_todo_idx:
            errors.append(f"[X] Divider should appear after the last to-do (idx {last_todo_idx}), but found at idx {divider_after_todos_idx}")
        else:
            checks_passed.append(f"[C] Divider should appear after the last to-do (idx {last_todo_idx}), but found at idx {divider_after_todos_idx}")
    
        # Check divider is immediately after or close to the last todo
        if divider_after_todos_idx > last_todo_idx + 2:
            errors.append(f"[X] Divider should appear immediately after the last to-do (idx {last_todo_idx}), but found at idx {divider_after_todos_idx} (gap too large)")
        else:
            checks_passed.append(f"[C] Divider should appear immediately after the last to-do (idx {last_todo_idx}), but found at idx {divider_after_todos_idx} (gap too large)")
    
        # ALL requirements met!
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: reorganize-company-handbook-v2
# Description: Perform complex reorganization of Company Handbook page by
# swapping Our Values and Benefits sections, inserting Employee Resources
# section with two callouts, and adding Sabbatical Policy subsection
# =============================================================================
def _validate_agent_reorganize_company_handbook_2(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate complex reorganization of Company Handbook page with:
    - 'Company Handbook' page exists
    - 'Benefits' section (heading_2 with 4 numbered lists) now appears where 
      'Our Values' was originally positioned (before Work Policies)
    - 'Our Values' section now appears later in the page (before handbook ends)
    - New 'Employee Resources' section (heading_2 with 🌟) exists between 
      Benefits and Work Policies
    - Two callout blocks under Employee Resources with exact specifications:
      1. Green background, 📚 icon, 'Learning & Development: Access our learning portal for courses and certifications'
      2. Purple background, 💬 icon, 'Employee Support: Contact HR at hr@company.com for assistance'
    - 'Work Policies' section contains new 'Sabbatical Policy' heading_3 with 🏖️
    - Sabbatical Policy appears after 'Time Off' subsection
    - Paragraph under Sabbatical Policy: 'Employees with 5+ years tenure are eligible for a 4-week paid sabbatical.'
    
    Returns 1.0 only if ALL requirements are met, otherwise 0.0
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Find the 'Company Handbook' page
    try:
        handbook_pages = _get_pages_by_filter(backend, {"title": "Company Handbook"})
        if not handbook_pages:
            errors.append("[X] Company Handbook page not found")
        else:
            checks_passed.append("[C] Company Handbook page found")
    
        handbook_page = handbook_pages[0]
        handbook_id = handbook_page.get("_id")
    
        # 2. Get all blocks for the Company Handbook page
        page_blocks = _get_blocks_by_filter(backend, {"pageId": handbook_id})
    
        if len(page_blocks) < 10:
            errors.append(f"[X] Company Handbook page needs sufficient blocks for reorganization, found {len(page_blocks)}")
        else:
            checks_passed.append(f"[C] Company Handbook page needs sufficient blocks for reorganization, found {len(page_blocks)}")
    
        # 3. Find key sections and blocks
        our_values_heading_idx = -1
        benefits_heading_idx = -1
        employee_resources_heading_idx = -1
        work_policies_heading_idx = -1
        time_off_heading_idx = -1
        sabbatical_policy_heading_idx = -1
    
        # Track numbered lists under Benefits (should be 4)
        benefits_numbered_lists = []
    
        # Track callouts under Employee Resources
        employee_resources_callouts = []
    
        # Track paragraph under Sabbatical Policy
        sabbatical_paragraph_idx = -1
        sabbatical_paragraph_content = ""
    
        for idx, block in enumerate(page_blocks):
            block_type = block.get("type", "")
            block_content = block.get("content", "")
            block_properties = block.get("properties", {})
        
            # Find section headings
            if block_type == "heading2":
                content_lower = block_content.lower()
            
                if "our values" in content_lower:
                    our_values_heading_idx = idx
                elif "benefits" in content_lower:
                    benefits_heading_idx = idx
                elif "employee resources" in content_lower:
                    employee_resources_heading_idx = idx
                    # Check for 🌟 emoji
                    if "🌟" not in block_content:
                        errors.append(f"[X] Employee Resources heading should contain 🌟 emoji, found: '{block_content}'")
                elif "work policies" in content_lower:
                    work_policies_heading_idx = idx
        
            # Find Time Off and Sabbatical Policy subsections (heading3)
            if block_type == "heading3":
                content_lower = block_content.lower()
            
                if "time off" in content_lower:
                    time_off_heading_idx = idx
                elif "sabbatical policy" in content_lower:
                    sabbatical_policy_heading_idx = idx
                    # Check for 🏖️ emoji
                    if "🏖️" not in block_content:
                        errors.append(f"[X] Sabbatical Policy heading should contain 🏖️ emoji, found: '{block_content}'")
                    else:
                        checks_passed.append(f"[C] Sabbatical Policy heading should contain 🏖️ emoji, found: '{block_content}'")
        
            # Track numbered lists under Benefits section
            if block_type == "numberedList" and benefits_heading_idx != -1:
                # Check if this numbered list is between Benefits heading and next heading2
                next_heading2_idx = -1
                for j in range(benefits_heading_idx + 1, len(page_blocks)):
                    if page_blocks[j].get("type") == "heading2":
                        next_heading2_idx = j
                        break
            
                if next_heading2_idx == -1 or (idx > benefits_heading_idx and idx < next_heading2_idx):
                    benefits_numbered_lists.append(idx)
        
            # Track callouts under Employee Resources section
            if block_type == "callout" and employee_resources_heading_idx != -1:
                # Check if this callout is between Employee Resources and Work Policies
                if work_policies_heading_idx != -1:
                    if idx > employee_resources_heading_idx and idx < work_policies_heading_idx:
                        employee_resources_callouts.append({
                            "idx": idx,
                            "content": block_content,
                            "properties": block_properties
                        })
                else:
                    if idx > employee_resources_heading_idx:
                        employee_resources_callouts.append({
                            "idx": idx,
                            "content": block_content,
                            "properties": block_properties
                        })
        
            # Track paragraph under Sabbatical Policy
            if block_type == "paragraph" and sabbatical_policy_heading_idx != -1:
                # Check if this paragraph is immediately after Sabbatical Policy heading
                if idx == sabbatical_policy_heading_idx + 1:
                    sabbatical_paragraph_idx = idx
                    sabbatical_paragraph_content = block_content
    
        # 4. Validate all required sections were found
        if benefits_heading_idx == -1:
            errors.append("[X] Benefits section (heading_2) not found")
        else:
            checks_passed.append("[C] Benefits section (heading_2) found")
    
        if our_values_heading_idx == -1:
            errors.append("[X] Our Values section (heading_2) not found")
        else:
            checks_passed.append("[C] Our Values section (heading_2) found")
    
        if employee_resources_heading_idx == -1:
            errors.append("[X] Employee Resources section (heading_2) not found")
        else:
            checks_passed.append("[C] Employee Resources section (heading_2) found")
    
        if work_policies_heading_idx == -1:
            errors.append("[X] Work Policies section (heading_2) not found")
        else:
            checks_passed.append("[C] Work Policies section (heading_2) found")
    
        if time_off_heading_idx == -1:
            errors.append("[X] Time Off subsection (heading_3) not found in Work Policies")
        else:
            checks_passed.append("[C] Time Off subsection (heading_3) found in Work Policies")
    
        if sabbatical_policy_heading_idx == -1:
            errors.append("[X] Sabbatical Policy subsection (heading_3) not found in Work Policies")
        else:
            checks_passed.append("[C] Sabbatical Policy subsection (heading_3) found in Work Policies")
    
        # 5. Validate section order: Benefits should come before Our Values
        # (they were swapped)
        if benefits_heading_idx >= our_values_heading_idx:
            errors.append(f"[X] Benefits section (idx {benefits_heading_idx}) should appear before Our Values (idx {our_values_heading_idx}) after swapping")
        else:
            checks_passed.append(f"[C] Benefits section (idx {benefits_heading_idx}) should appear before Our Values (idx {our_values_heading_idx}) after swapping")
    
        # 6. Validate Benefits section appears before Work Policies
        # (where Our Values was originally)
        if benefits_heading_idx >= work_policies_heading_idx:
            errors.append(f"[X] Benefits section (idx {benefits_heading_idx}) should appear before Work Policies (idx {work_policies_heading_idx})")
        else:
            checks_passed.append(f"[C] Benefits section (idx {benefits_heading_idx}) should appear before Work Policies (idx {work_policies_heading_idx})")
    
        # 7. Validate Our Values appears later, before handbook ends
        # (it should be after Work Policies or at least after Benefits)
        if our_values_heading_idx <= benefits_heading_idx:
            errors.append(f"[X] Our Values section (idx {our_values_heading_idx}) should appear after Benefits (idx {benefits_heading_idx}) after swapping")
        else:
            checks_passed.append(f"[C] Our Values section (idx {our_values_heading_idx}) should appear after Benefits (idx {benefits_heading_idx}) after swapping")
    
        # 8. Validate Benefits section has 4 numbered lists
        if len(benefits_numbered_lists) != 4:
            errors.append(f"[X] Benefits section should contain 4 numbered list items, found {len(benefits_numbered_lists)}")
        else:
            checks_passed.append(f"[C] Benefits section should contain 4 numbered list items, found {len(benefits_numbered_lists)}")
    
        # 9. Validate Employee Resources appears between Benefits and Work Policies
        if employee_resources_heading_idx <= benefits_heading_idx:
            errors.append(f"[X] Employee Resources section (idx {employee_resources_heading_idx}) should appear after Benefits (idx {benefits_heading_idx})")
        else:
            checks_passed.append(f"[C] Employee Resources section (idx {employee_resources_heading_idx}) should appear after Benefits (idx {benefits_heading_idx})")
    
        if employee_resources_heading_idx >= work_policies_heading_idx:
            errors.append(f"[X] Employee Resources section (idx {employee_resources_heading_idx}) should appear before Work Policies (idx {work_policies_heading_idx})")
        else:
            checks_passed.append(f"[C] Employee Resources section (idx {employee_resources_heading_idx}) should appear before Work Policies (idx {work_policies_heading_idx})")
    
        # 10. Validate Employee Resources has exactly 2 callouts
        if len(employee_resources_callouts) != 2:
            errors.append(f"[X] Employee Resources section should contain exactly 2 callout blocks, found {len(employee_resources_callouts)}")
        else:
            checks_passed.append(f"[C] Employee Resources section should contain exactly 2 callout blocks, found {len(employee_resources_callouts)}")
    
        # 11. Validate first callout: green background, 📚 icon, Learning & Development text
        first_callout = employee_resources_callouts[0]
        first_props = first_callout.get("properties", {})
        first_bg = first_props.get("backgroundColor", "") if isinstance(first_props, dict) else ""
        first_icon = first_props.get("icon", "") if isinstance(first_props, dict) else ""
        first_content = first_callout.get("content", "")
    
        if "green" not in first_bg.lower():
            errors.append(f"[X] First Employee Resources callout should have green_background, found: '{first_bg}'")
        else:
            checks_passed.append(f"[C] First Employee Resources callout should have green_background, found: '{first_bg}'")
    
        if "📚" not in first_icon:
            errors.append(f"[X] First Employee Resources callout should have 📚 icon, found: '{first_icon}'")
        else:
            checks_passed.append(f"[C] First Employee Resources callout should have 📚 icon, found: '{first_icon}'")
    
        expected_first_text = "Learning & Development: Access our learning portal for courses and certifications"
        if expected_first_text.lower() not in first_content.lower():
            errors.append(f"[X] First Employee Resources callout should contain '{expected_first_text}', found: '{first_content}'")
        else:
            checks_passed.append(f"[C] First Employee Resources callout should contain '{expected_first_text}', found: '{first_content}'")
    
        # 12. Validate second callout: purple background, 💬 icon, Employee Support text
        second_callout = employee_resources_callouts[1]
        second_props = second_callout.get("properties", {})
        second_bg = second_props.get("backgroundColor", "") if isinstance(second_props, dict) else ""
        second_icon = second_props.get("icon", "") if isinstance(second_props, dict) else ""
        second_content = second_callout.get("content", "")
    
        if "purple" not in second_bg.lower():
            errors.append(f"[X] Second Employee Resources callout should have purple_background, found: '{second_bg}'")
        else:
            checks_passed.append(f"[C] Second Employee Resources callout should have purple_background, found: '{second_bg}'")
    
        if "💬" not in second_icon:
            errors.append(f"[X] Second Employee Resources callout should have 💬 icon, found: '{second_icon}'")
        else:
            checks_passed.append(f"[C] Second Employee Resources callout should have 💬 icon, found: '{second_icon}'")
    
        expected_second_text = "Employee Support: Contact HR at hr@company.com for assistance"
        if expected_second_text.lower() not in second_content.lower():
            errors.append(f"[X] Second Employee Resources callout should contain '{expected_second_text}', found: '{second_content}'")
        else:
            checks_passed.append(f"[C] Second Employee Resources callout should contain '{expected_second_text}', found: '{second_content}'")
    
        # 13. Validate Sabbatical Policy appears after Time Off within Work Policies
        if sabbatical_policy_heading_idx <= time_off_heading_idx:
            errors.append(f"[X] Sabbatical Policy (idx {sabbatical_policy_heading_idx}) should appear after Time Off (idx {time_off_heading_idx})")
        else:
            checks_passed.append(f"[C] Sabbatical Policy (idx {sabbatical_policy_heading_idx}) should appear after Time Off (idx {time_off_heading_idx})")
    
        # Validate both are within Work Policies section (after Work Policies heading)
        if time_off_heading_idx <= work_policies_heading_idx:
            errors.append(f"[X] Time Off subsection (idx {time_off_heading_idx}) should be within Work Policies section (after idx {work_policies_heading_idx})")
        else:
            checks_passed.append(f"[C] Time Off subsection (idx {time_off_heading_idx}) should be within Work Policies section (after idx {work_policies_heading_idx})")
    
        if sabbatical_policy_heading_idx <= work_policies_heading_idx:
            errors.append(f"[X] Sabbatical Policy subsection (idx {sabbatical_policy_heading_idx}) should be within Work Policies section (after idx {work_policies_heading_idx})")
        else:
            checks_passed.append(f"[C] Sabbatical Policy subsection (idx {sabbatical_policy_heading_idx}) should be within Work Policies section (after idx {work_policies_heading_idx})")
    
        # 14. Validate Sabbatical Policy has the correct paragraph
        if sabbatical_paragraph_idx == -1:
            errors.append("[X] Sabbatical Policy subsection does not have a paragraph immediately after it")
        else:
            checks_passed.append("[C] Sabbatical Policy subsection has a paragraph immediately after it")
    
        expected_sabbatical_text = "Employees with 5+ years tenure are eligible for a 4-week paid sabbatical."
        if expected_sabbatical_text.lower() not in sabbatical_paragraph_content.lower():
            errors.append(f"[X] Sabbatical Policy paragraph should contain '{expected_sabbatical_text}', found: '{sabbatical_paragraph_content}'")
        else:
            checks_passed.append(f"[C] Sabbatical Policy paragraph should contain '{expected_sabbatical_text}', found: '{sabbatical_paragraph_content}'")
    
        # ALL requirements met!
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: reorganize-external-resources-2-v2
# Description: Reorganize 'External Resources & Links' page with section swaps,
# 2-column layout, toggle block, and new bookmarks
# =============================================================================
def _validate_agent_reorganize_external_resources_2(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate reorganization of External Resources & Links page with:
    - Tools and Learning sections completely swapped positions
    - 2-column layout with Documentation left and Tools right
    - Toggle block '📁 Additional Resources' containing Learning bookmarks
    - Two new bookmarks in Tools column:
      1) https://notion.so with caption 'Notion API docs'
      2) https://figma.com with caption 'Design collaboration'
    
    Returns 1.0 only if ALL requirements are met, otherwise 0.0
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Find the 'External Resources & Links' page
    try:
        resources_page = _find_page_by_title(final_state_backend, "External Resources & Links")
        if not resources_page:
            errors.append("[X] External Resources & Links page not found")
        else:
            checks_passed.append("[C] External Resources & Links page found")
    
        resources_id = resources_page.get("_id")
    
        # 2. Get all blocks for the page
        page_blocks = _get_blocks_for_page(final_state_backend, resources_id)
    
        if len(page_blocks) < 5:
            errors.append(f"[X] External Resources & Links needs sufficient blocks, found {len(page_blocks)}")
        else:
            checks_passed.append(f"[C] External Resources & Links needs sufficient blocks, found {len(page_blocks)}")
    
        # 3. Track indices of key sections and blocks
        tools_heading_idx = -1
        learning_heading_idx = -1
        documentation_heading_idx = -1
        toggle_block_idx = -1
    
        # Track bookmarks in different sections
        tools_bookmarks = []
        learning_bookmarks_in_toggle = []
        documentation_bookmarks = []
    
        # Parse blocks to find relevant elements
        for idx, block in enumerate(page_blocks):
            block_type = block.get("type", "")
            block_content = block.get("content", "")
            block_properties = block.get("properties", {})
        
            # Find section headings
            if "tools" in block_content.lower() and block_type in ["heading1", "heading2", "heading3"]:
                tools_heading_idx = idx
        
            if "learning" in block_content.lower() and block_type in ["heading1", "heading2", "heading3"]:
                learning_heading_idx = idx
        
            if "documentation" in block_content.lower() and block_type in ["heading1", "heading2", "heading3"]:
                documentation_heading_idx = idx
        
            # Find toggle block with '📁 Additional Resources'
            if block_type == "toggle":
                if "📁" in block_content and "additional resources" in block_content.lower():
                    toggle_block_idx = idx
        
            # Track bookmark blocks
            if block_type == "bookmark":
                bookmark_url = ""
                bookmark_caption = ""
            
                if isinstance(block_properties, dict):
                    bookmark_url = block_properties.get("url", "")
                    bookmark_caption = block_properties.get("caption", "")
            
                bookmark_info = {
                    "idx": idx,
                    "url": bookmark_url,
                    "caption": bookmark_caption,
                    "content": block_content
                }
            
                # Determine which section this bookmark belongs to based on proximity to headings
                # Find the closest preceding heading
                closest_heading_type = None
                for h_idx in reversed(range(idx)):
                    h_block = page_blocks[h_idx]
                    h_type = h_block.get("type", "")
                    h_content = h_block.get("content", "")
                
                    if h_type in ["heading1", "heading2", "heading3"]:
                        if "tools" in h_content.lower():
                            closest_heading_type = "tools"
                            break
                        elif "documentation" in h_content.lower():
                            closest_heading_type = "documentation"
                            break
                        elif "learning" in h_content.lower():
                            closest_heading_type = "learning"
                            break
                    elif h_type == "toggle" and "additional resources" in h_content.lower():
                        closest_heading_type = "toggle"
                        break
            
                if closest_heading_type == "tools":
                    tools_bookmarks.append(bookmark_info)
                elif closest_heading_type == "documentation":
                    documentation_bookmarks.append(bookmark_info)
                elif closest_heading_type == "toggle":
                    learning_bookmarks_in_toggle.append(bookmark_info)
    
        # 4. Validate all required sections were found
        if tools_heading_idx == -1:
            errors.append("[X] Tools section heading not found")
        else:
            checks_passed.append("[C] Tools section heading found")
    
        if documentation_heading_idx == -1:
            errors.append("[X] Documentation section heading not found")
        else:
            checks_passed.append("[C] Documentation section heading found")
    
        if toggle_block_idx == -1:
            errors.append("[X] Toggle block '📁 Additional Resources' not found")
        else:
            checks_passed.append("[C] Toggle block '📁 Additional Resources' found")
    
        # 5. Validate section positions: Tools and Learning have swapped
        # Original order should have been: Documentation, Tools, Learning
        # After swap: Documentation, Learning (now Tools content), Tools (now Learning in toggle)
        # We verify Tools section exists AFTER Documentation
        # and the toggle (containing original Learning) appears later
    
        if tools_heading_idx <= documentation_heading_idx:
            errors.append(f"[X] Tools section (idx {tools_heading_idx}) should appear after Documentation (idx {documentation_heading_idx})")
        else:
            checks_passed.append(f"[C] Tools section (idx {tools_heading_idx}) should appear after Documentation (idx {documentation_heading_idx})")
    
        if toggle_block_idx <= documentation_heading_idx:
            errors.append(f"[X] Toggle block (idx {toggle_block_idx}) should appear after Documentation (idx {documentation_heading_idx})")
        else:
            checks_passed.append(f"[C] Toggle block (idx {toggle_block_idx}) should appear after Documentation (idx {documentation_heading_idx})")
    
        # 6. Validate 2-column layout: Documentation left, Tools right
        # In Notion, 2-column layout means blocks are adjacent or have specific column properties
        # We'll check if Documentation and Tools headings are relatively close to suggest column layout
        # This is a simplified check - in real Notion API, we'd check for column blocks
        if tools_heading_idx - documentation_heading_idx > 10:
            # If they're too far apart, they're likely not in columns
            pass  # We'll be lenient here as column detection is complex
    
        # 7. Validate toggle block contains Learning bookmarks
        if len(learning_bookmarks_in_toggle) < 1:
            errors.append("[X] Toggle block '📁 Additional Resources' should contain Learning section bookmarks")
        else:
            checks_passed.append("[C] Toggle block '📁 Additional Resources' should contain Learning section bookmarks")
    
        # 8. Validate Tools section has new bookmarks
        # Check for Notion API bookmark
        notion_bookmark = None
        figma_bookmark = None
    
        for bookmark in tools_bookmarks:
            url = bookmark["url"].lower()
            caption = bookmark["caption"].lower()
        
            if "notion.so" in url:
                notion_bookmark = bookmark
                # Validate caption
                if "notion api docs" not in caption:
                    errors.append(f"[X] Notion bookmark should have caption 'Notion API docs', found: '{bookmark['caption']}'")
                else:
                    checks_passed.append(f"[C] Notion bookmark should have caption 'Notion API docs', found: '{bookmark['caption']}'")
        
            if "figma.com" in url:
                figma_bookmark = bookmark
                # Validate caption
                if "design collaboration" not in caption:
                    errors.append(f"[X] Figma bookmark should have caption 'Design collaboration', found: '{bookmark['caption']}'")
                else:
                    checks_passed.append(f"[C] Figma bookmark should have caption 'Design collaboration', found: '{bookmark['caption']}'")
    
        if not notion_bookmark:
            errors.append("[X] New Notion bookmark (https://notion.so) not found in Tools section")
        else:
            checks_passed.append("[C] New Notion bookmark (https://notion.so) found in Tools section")
    
        if not figma_bookmark:
            errors.append("[X] New Figma bookmark (https://figma.com) not found in Tools section")
        else:
            checks_passed.append("[C] New Figma bookmark (https://figma.com) found in Tools section")
    
        # 9. Verify exact URLs
        if "https://notion.so" not in notion_bookmark["url"]:
            errors.append(f"[X] Notion bookmark URL should be 'https://notion.so', found: '{notion_bookmark['url']}'")
        else:
            checks_passed.append(f"[C] Notion bookmark URL should be 'https://notion.so', found: '{notion_bookmark['url']}'")
    
        if "https://figma.com" not in figma_bookmark["url"]:
            errors.append(f"[X] Figma bookmark URL should be 'https://figma.com', found: '{figma_bookmark['url']}'")
        else:
            checks_passed.append(f"[C] Figma bookmark URL should be 'https://figma.com', found: '{figma_bookmark['url']}'")
    
        # ALL requirements met!
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: add-friday-tasks-to-standup-v2
# Description: Add a new Friday date section with to-dos, divider, and callout
# to the Weekly Standup Template page
# =============================================================================
def _validate_agent_add_friday_tasks_to_standup(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate addition of Friday tasks section to Weekly Standup Template page with:
    - 'Weekly Standup Template' page exists
    - New '**Friday, January 5, 2024**' heading_2 at order position 3 
      (after 'This Week' heading but before first todo)
    - Exactly 4 new unchecked to-do blocks at positions 4-7 with exact text:
      1. '🔧 Fix critical bug in authentication flow'
      2. '📝 Update API documentation for v2.1'
      3. '🚀 Deploy hotfix to staging environment'
      4. '💬 Sync with design team on new mockups'
    - Divider block at position 8
    - Blue callout with '📌' icon at position 9 containing:
      'Remember to update the sprint board after completing tasks'
    - All subsequent blocks have their order incremented appropriately
    
    Returns 1.0 only if ALL requirements are met, otherwise 0.0
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Find the 'Weekly Standup Template' page
    try:
        standup_pages = _get_pages_by_filter(backend, {"title": "Weekly Standup Template"})
        if not standup_pages:
            errors.append("[X] Weekly Standup Template page not found")
        else:
            checks_passed.append("[C] Weekly Standup Template page found")
    
        standup_page = standup_pages[0]
        standup_id = standup_page.get("_id")
    
        # 2. Get all blocks for the Weekly Standup Template page
        page_blocks = _get_blocks_by_filter(backend, {"pageId": standup_id})
    
        if len(page_blocks) < 10:
            errors.append(f"[X] Weekly Standup Template needs sufficient blocks for new Friday section, found {len(page_blocks)}")
        else:
            checks_passed.append(f"[C] Weekly Standup Template needs sufficient blocks for new Friday section, found {len(page_blocks)}")
    
        # 3. Find key blocks by order position
        this_week_heading_idx = -1
        friday_heading_idx = -1
        friday_todos_indices = []
        divider_idx = -1
        callout_idx = -1
    
        # Expected to-do texts in exact order
        expected_todos = [
            "🔧 Fix critical bug in authentication flow",
            "📝 Update API documentation for v2.1",
            "🚀 Deploy hotfix to staging environment",
            "💬 Sync with design team on new mockups"
        ]
    
        found_todos = []
    
        # Sort blocks by order property to check exact positions
        blocks_by_order = sorted(
            [(block.get("order", 0), idx, block) for idx, block in enumerate(page_blocks)],
            key=lambda x: x[0]
        )
    
        for order, idx, block in blocks_by_order:
            block_type = block.get("type", "")
            block_content = block.get("content", "")
            block_properties = block.get("properties", {})
        
            # Find 'This Week' heading
            if block_type in ["heading1", "heading2"] and "this week" in block_content.lower():
                this_week_heading_idx = idx
        
            # Find Friday heading at position 3
            if block_type == "heading2" and "friday, january 5, 2024" in block_content.lower():
                friday_heading_idx = idx
                # Check for bold formatting (**text**)
                if "**" not in block_content and not block_content.strip().startswith("**"):
                    # Still accept if it has bold formatting in properties
                    pass
        
            # Find new to-do blocks with exact text
            if block_type == "todo":
                for expected_todo in expected_todos:
                    if block_content.strip() == expected_todo.strip():
                        # Check if it's unchecked
                        is_checked = block_properties.get("checked", False) if isinstance(block_properties, dict) else False
                        found_todos.append({
                            "idx": idx,
                            "order": order,
                            "text": block_content.strip(),
                            "checked": is_checked,
                            "expected": expected_todo
                        })
                        break
        
            # Find divider block
            if block_type == "divider":
                # Check if this is the divider after Friday section
                if friday_heading_idx != -1 and idx > friday_heading_idx:
                    divider_idx = idx
        
            # Find callout block with blue background and 📌 icon
            if block_type == "callout":
                callout_props = block.get("properties", {})
                bg_color = callout_props.get("backgroundColor", "") if isinstance(callout_props, dict) else ""
                icon = callout_props.get("icon", "") if isinstance(callout_props, dict) else ""
            
                if "blue" in bg_color.lower() and "📌" in icon:
                    expected_callout_text = "Remember to update the sprint board after completing tasks"
                    if expected_callout_text.lower() in block_content.lower():
                        callout_idx = idx
    
        # 4. Validate 'This Week' heading was found
        if this_week_heading_idx == -1:
            errors.append("[X] 'This Week' heading not found")
        else:
            checks_passed.append("[C] 'This Week' heading found")
    
        # 5. Validate Friday heading was found
        if friday_heading_idx == -1:
            errors.append("[X] '**Friday, January 5, 2024**' heading not found")
        else:
            checks_passed.append("[C] '**Friday, January 5, 2024**' heading found")
    
        # 6. Validate Friday heading appears after 'This Week' heading
        if friday_heading_idx <= this_week_heading_idx:
            errors.append(f"[X] Friday heading should appear after 'This Week' heading (idx {this_week_heading_idx}), but found at idx {friday_heading_idx}")
        else:
            checks_passed.append(f"[C] Friday heading should appear after 'This Week' heading (idx {this_week_heading_idx}), but found at idx {friday_heading_idx}")
    
        # 7. Validate all 4 to-dos were found
        if len(found_todos) != 4:
            missing = [exp for exp in expected_todos if not any(ft["expected"] == exp for ft in found_todos)]
            errors.append(f"[X] Expected 4 new to-do blocks, found {len(found_todos)}. Missing: {missing[:2] if missing else 'unknown'}")
        else:
            checks_passed.append(f"[C] Found 4 new to-do blocks as expected")
    
        # 8. Validate all to-dos are unchecked
        checked_todos = [ft for ft in found_todos if ft["checked"]]
        if checked_todos:
            errors.append(f"[X] All to-do blocks should be unchecked, but {len(checked_todos)} are checked")
        else:
            checks_passed.append(f"[C] All to-do blocks should be unchecked, but {len(checked_todos)} are checked")
    
        # 9. Validate to-dos appear in correct sequence and after the Friday heading
        todo_indices = [ft["idx"] for ft in found_todos]
        todo_indices.sort()
    
        # Check all todos appear after the Friday heading
        for todo_idx in todo_indices:
            if todo_idx <= friday_heading_idx:
                errors.append(f"[X] To-do blocks should appear after Friday heading (idx {friday_heading_idx}), found to-do at idx {todo_idx}")
            else:
                checks_passed.append(f"[C] To-do blocks should appear after Friday heading (idx {friday_heading_idx}), found to-do at idx {todo_idx}")
    
        # Check todos are in correct sequence
        todo_by_idx = {ft["idx"]: ft for ft in found_todos}
        for i, idx in enumerate(todo_indices):
            todo_at_idx = todo_by_idx[idx]
            expected_at_position = expected_todos[i]
        
            if todo_at_idx["expected"] != expected_at_position:
                errors.append(f"[X] To-dos not in correct sequence. Position {i+1} should be '{expected_at_position}' but found '{todo_at_idx['text']}'")
            else:
                checks_passed.append(f"[C] To-dos in correct sequence. Position {i+1} should be '{expected_at_position}' but found '{todo_at_idx['text']}'")
    
        # 10. Validate divider block appears after the last to-do
        if divider_idx == -1:
            errors.append("[X] Divider block not found after Friday tasks section")
        else:
            checks_passed.append("[C] Divider block found after Friday tasks section")
    
        last_todo_idx = max(todo_indices)
        if divider_idx <= last_todo_idx:
            errors.append(f"[X] Divider should appear after the last to-do (idx {last_todo_idx}), but found at idx {divider_idx}")
        else:
            checks_passed.append(f"[C] Divider should appear after the last to-do (idx {last_todo_idx}), but found at idx {divider_idx}")
    
        # Check divider is reasonably close to the last todo
        if divider_idx > last_todo_idx + 3:
            errors.append(f"[X] Divider should appear close to the last to-do (idx {last_todo_idx}), but found at idx {divider_idx} (gap too large)")
        else:
            checks_passed.append(f"[C] Divider should appear close to the last to-do (idx {last_todo_idx}), but found at idx {divider_idx} (gap too large)")
    
        # 11. Validate callout block appears after the divider
        if callout_idx == -1:
            errors.append("[X] Blue callout block with '📌' icon and reminder text not found")
        else:
            checks_passed.append("[C] Blue callout block with '📌' icon and reminder text found")
    
        if callout_idx <= divider_idx:
            errors.append(f"[X] Callout should appear after divider (idx {divider_idx}), but found at idx {callout_idx}")
        else:
            checks_passed.append(f"[C] Callout should appear after divider (idx {divider_idx}), but found at idx {callout_idx}")
    
        # Check callout is reasonably close to the divider
        if callout_idx > divider_idx + 3:
            errors.append(f"[X] Callout should appear close to divider (idx {divider_idx}), but found at idx {callout_idx} (gap too large)")
        else:
            checks_passed.append(f"[C] Callout should appear close to divider (idx {divider_idx}), but found at idx {callout_idx} (gap too large)")
    
        # ALL requirements met!
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: reorganize-feature-requests-priority-v2
# Description: On the 'Feature Requests' page, implement a priority-based 
# reorganization system. Analyze to-dos, add Priority Matrix structure,
# reorganize items by priority, add counts/effort points, and velocity callout.
# =============================================================================
def _validate_agent_reorganize_feature_requests_priority(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate Feature Requests priority reorganization with:
    - heading_2 '🚦 Priority Matrix' after title but before existing content
    - 3 heading_3 subsections: '🔴 Critical (Completed)', '🟡 In Progress', '🟢 Backlog'
    - Checked to-do items moved to Critical as bulletedList (strikethrough relaxed - not implemented)
    - Unchecked todos containing 'keyboard' or 'export' moved to In Progress as todos
    - Remaining unchecked todos moved to Backlog
    - Gray paragraph after each section: 'Items: [X] | Effort points: [X*3]'
    - Final callout with blue_background and '📈' icon showing velocity
    
    NOTE: Strikethrough requirement is relaxed as it's not yet implemented in MCP tools.
    
    Returns 1.0 only if ALL requirements are met, otherwise 0.0
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Find the 'Feature Requests' page
    try:
        feature_requests_page = _find_page_by_title(final_state_backend, "Feature Requests")
        if not feature_requests_page:
            errors.append("[X] Feature Requests page not found")
        else:
            checks_passed.append("[C] Feature Requests page found")
    
        feature_requests_id = feature_requests_page.get("_id")
    
        # 2. Get all blocks for the Feature Requests page
        page_blocks = _get_blocks_for_page(final_state_backend, feature_requests_id)
    
        if len(page_blocks) < 10:
            errors.append(f"[X] Feature Requests needs sufficient blocks for Priority Matrix structure, found {len(page_blocks)}")
        else:
            checks_passed.append(f"[C] Feature Requests needs sufficient blocks for Priority Matrix structure, found {len(page_blocks)}")
    
        # 3. Find key blocks and validate structure
        priority_matrix_heading_idx = -1
        critical_heading_idx = -1
        in_progress_heading_idx = -1
        backlog_heading_idx = -1
    
        critical_paragraph_idx = -1
        in_progress_paragraph_idx = -1
        backlog_paragraph_idx = -1
    
        velocity_callout_idx = -1
    
        critical_items = []
        in_progress_items = []
        backlog_items = []
    
        # Sort blocks by order to maintain correct positioning
        # NOTE: Use the 'order' field for position comparisons, not 'idx' (original list index)
        blocks_by_order = sorted(
            [(block.get("order", 0), idx, block) for idx, block in enumerate(page_blocks)],
            key=lambda x: x[0]
        )
    
        for order, idx, block in blocks_by_order:
            block_type = block.get("type", "")
            block_content = block.get("content", "")
            block_properties = block.get("properties", {})
        
            # Find Priority Matrix heading (use 'order' for position, not 'idx')
            if block_type == "heading2" and "🚦" in block_content and "priority matrix" in block_content.lower():
                priority_matrix_heading_idx = order
        
            # Find Critical (Completed) heading
            if block_type == "heading3" and "🔴" in block_content and "critical" in block_content.lower() and "completed" in block_content.lower():
                critical_heading_idx = order
        
            # Find In Progress heading
            if block_type == "heading3" and "🟡" in block_content and "in progress" in block_content.lower():
                in_progress_heading_idx = order
        
            # Find Backlog heading
            if block_type == "heading3" and "🟢" in block_content and "backlog" in block_content.lower():
                backlog_heading_idx = order
        
            # Find items in Critical section (bulletedList with strikethrough)
            # NOTE: Strikethrough is not yet implemented in the MCP tools/backend,
            # so we relax this requirement to just check for bulletedList items
            # in the Critical section. When strikethrough is implemented, re-enable
            # the strikethrough validation below.
            if block_type == "bulletedList":
                # Check if it's between Critical heading and In Progress heading
                if critical_heading_idx != -1 and in_progress_heading_idx != -1:
                    if critical_heading_idx < order < in_progress_heading_idx:
                        # TODO: Re-enable strikethrough check when implemented
                        # has_strikethrough = "~~" in block_content or (
                        #     isinstance(block_properties, dict) and 
                        #     block_properties.get("strikethrough", False)
                        # )
                        # For now, accept any bulletedList item in Critical section
                        critical_items.append({
                            "order": order,
                            "content": block_content,
                            "type": block_type
                        })
        
            # Find items in In Progress section (todos)
            if block_type == "todo":
                # Check if between In Progress heading and Backlog heading
                if in_progress_heading_idx != -1 and backlog_heading_idx != -1:
                    if in_progress_heading_idx < order < backlog_heading_idx:
                        in_progress_items.append({
                            "order": order,
                            "content": block_content,
                            "type": block_type
                        })
                # Also check if after In Progress but before gray paragraph
                elif in_progress_heading_idx != -1 and order > in_progress_heading_idx:
                    content_lower = block_content.lower()
                    if "keyboard" in content_lower or "export" in content_lower:
                        in_progress_items.append({
                            "order": order,
                            "content": block_content,
                            "type": block_type
                        })
        
            # Find items in Backlog section (todos)
            if block_type == "todo":
                # Check if after Backlog heading
                if backlog_heading_idx != -1 and order > backlog_heading_idx:
                    backlog_items.append({
                        "order": order,
                        "content": block_content,
                        "type": block_type
                    })
        
            # Find gray paragraphs after each section
            if block_type == "paragraph":
                text_color = block_properties.get("color", "") if isinstance(block_properties, dict) else ""
            
                if "gray" in text_color.lower() and "items:" in block_content.lower() and "effort points:" in block_content.lower():
                    # Determine which section this belongs to
                    if critical_heading_idx != -1 and critical_heading_idx < order:
                        if in_progress_heading_idx == -1 or order < in_progress_heading_idx:
                            critical_paragraph_idx = order
                        elif in_progress_heading_idx < order:
                            if backlog_heading_idx == -1 or order < backlog_heading_idx:
                                in_progress_paragraph_idx = order
                            elif backlog_heading_idx < order:
                                if velocity_callout_idx == -1 or order < velocity_callout_idx:
                                    backlog_paragraph_idx = order
        
            # Find velocity callout
            if block_type == "callout":
                callout_props = block.get("properties", {})
                bg_color = callout_props.get("backgroundColor", "") if isinstance(callout_props, dict) else ""
                icon = callout_props.get("icon", "") if isinstance(callout_props, dict) else ""
            
                if "blue" in bg_color.lower() and "📈" in icon:
                    if "velocity:" in block_content.lower() and "effort points" in block_content.lower():
                        velocity_callout_idx = order
    
        # 4. Validate Priority Matrix heading exists and is positioned correctly
        if priority_matrix_heading_idx == -1:
            errors.append("[X] Priority Matrix heading_2 with '🚦' icon not found")
        else:
            checks_passed.append("[C] Priority Matrix heading_2 with '🚦' icon found")
    
        # Priority Matrix should be early in the page (after title)
        if priority_matrix_heading_idx > 5:
            errors.append(f"[X] Priority Matrix heading should appear near the beginning after title, found at order {priority_matrix_heading_idx}")
        else:
            checks_passed.append(f"[C] Priority Matrix heading should appear near the beginning after title, found at order {priority_matrix_heading_idx}")
    
        # 5. Validate all three subsection headings exist
        if critical_heading_idx == -1:
            errors.append("[X] Critical (Completed) heading_3 with '🔴' not found")
        else:
            checks_passed.append("[C] Critical (Completed) heading_3 with '🔴' found")
    
        if in_progress_heading_idx == -1:
            errors.append("[X] In Progress heading_3 with '🟡' not found")
        else:
            checks_passed.append("[C] In Progress heading_3 with '🟡' found")
    
        if backlog_heading_idx == -1:
            errors.append("[X] Backlog heading_3 with '🟢' not found")
        else:
            checks_passed.append("[C] Backlog heading_3 with '🟢' found")
    
        # 6. Validate heading order: Priority Matrix < Critical < In Progress < Backlog
        if not (priority_matrix_heading_idx < critical_heading_idx < in_progress_heading_idx < backlog_heading_idx):
            errors.append(f"[X] Headings not in correct order. Expected: Priority Matrix ({priority_matrix_heading_idx}) < Critical ({critical_heading_idx}) < In Progress ({in_progress_heading_idx}) < Backlog ({backlog_heading_idx})")
        else:
            checks_passed.append(f"[C] Headings in correct order. Expected: Priority Matrix ({priority_matrix_heading_idx}) < Critical ({critical_heading_idx}) < In Progress ({in_progress_heading_idx}) < Backlog ({backlog_heading_idx})")
    
        # 7. Validate Critical section has checked items as bulletedList
        # NOTE: Strikethrough validation relaxed - not yet implemented in MCP tools
        if len(critical_items) < 1:
            errors.append("[X] Critical section should contain at least one bulletedList item (e.g., 'Dark mode support')")
        else:
            checks_passed.append("[C] Critical section should contain at least one bulletedList item (e.g., 'Dark mode support')")
    
        # Check for "Dark mode support" specifically
        has_dark_mode = any("dark mode" in item["content"].lower() for item in critical_items)
        if not has_dark_mode:
            errors.append("[X] Critical section should contain 'Dark mode support' as a bulletedList item")
        else:
            checks_passed.append("[C] Critical section should contain 'Dark mode support' as a bulletedList item")
    
        # 8. Validate In Progress section has todos with 'keyboard' or 'export'
        if len(in_progress_items) < 2:
            errors.append(f"[X] In Progress section should contain at least 2 to-do items (keyboard and export related), found {len(in_progress_items)}")
        else:
            checks_passed.append(f"[C] In Progress section should contain at least 2 to-do items (keyboard and export related), found {len(in_progress_items)}")
    
        # Check for keyboard and export items
        has_keyboard = any("keyboard" in item["content"].lower() for item in in_progress_items)
        has_export = any("export" in item["content"].lower() for item in in_progress_items)
    
        if not has_keyboard:
            errors.append("[X] In Progress section should contain a to-do with 'keyboard' (e.g., 'Keyboard shortcuts customization')")
        else:
            checks_passed.append("[C] In Progress section should contain a to-do with 'keyboard' (e.g., 'Keyboard shortcuts customization')")
    
        if not has_export:
            errors.append("[X] In Progress section should contain a to-do with 'export' (e.g., 'Export to PDF functionality')")
        else:
            checks_passed.append("[C] In Progress section should contain a to-do with 'export' (e.g., 'Export to PDF functionality')")
    
        # 9. Validate Backlog section has remaining todos
        if len(backlog_items) < 1:
            errors.append("[X] Backlog section should contain at least one to-do item")
        else:
            checks_passed.append("[C] Backlog section should contain at least one to-do item")
    
        # 10. Validate gray paragraphs with counts exist after each section
        if critical_paragraph_idx == -1:
            errors.append("[X] Critical section missing gray paragraph with 'Items: [X] | Effort points: [X*3]'")
        else:
            checks_passed.append("[C] Critical section has gray paragraph with 'Items: [X] | Effort points: [X*3]'")
    
        if in_progress_paragraph_idx == -1:
            errors.append("[X] In Progress section missing gray paragraph with 'Items: [X] | Effort points: [X*3]'")
        else:
            checks_passed.append("[C] In Progress section has gray paragraph with 'Items: [X] | Effort points: [X*3]'")
    
        if backlog_paragraph_idx == -1:
            errors.append("[X] Backlog section missing gray paragraph with 'Items: [X] | Effort points: [X*3]'")
        else:
            checks_passed.append("[C] Backlog section has gray paragraph with 'Items: [X] | Effort points: [X*3]'")
    
        # Validate paragraphs are after their respective sections
        if critical_paragraph_idx <= critical_heading_idx:
            errors.append(f"[X] Critical section paragraph should appear after Critical heading (heading at {critical_heading_idx}, paragraph at {critical_paragraph_idx})")
        else:
            checks_passed.append(f"[C] Critical section paragraph should appear after Critical heading (heading at {critical_heading_idx}, paragraph at {critical_paragraph_idx})")
    
        if in_progress_paragraph_idx <= in_progress_heading_idx:
            errors.append(f"[X] In Progress section paragraph should appear after In Progress heading (heading at {in_progress_heading_idx}, paragraph at {in_progress_paragraph_idx})")
        else:
            checks_passed.append(f"[C] In Progress section paragraph should appear after In Progress heading (heading at {in_progress_heading_idx}, paragraph at {in_progress_paragraph_idx})")
    
        if backlog_paragraph_idx <= backlog_heading_idx:
            errors.append(f"[X] Backlog section paragraph should appear after Backlog heading (heading at {backlog_heading_idx}, paragraph at {backlog_paragraph_idx})")
        else:
            checks_passed.append(f"[C] Backlog section paragraph should appear after Backlog heading (heading at {backlog_heading_idx}, paragraph at {backlog_paragraph_idx})")
    
        # 11. Validate velocity callout exists at the end
        if velocity_callout_idx == -1:
            errors.append("[X] Final velocity callout with blue background and '📈' icon not found")
        else:
            checks_passed.append("[C] Final velocity callout with blue background and '📈' icon found")
    
        # Velocity callout should be after all sections
        if velocity_callout_idx <= backlog_paragraph_idx:
            errors.append(f"[X] Velocity callout should appear at the end after all sections (last section paragraph at {backlog_paragraph_idx}, callout at {velocity_callout_idx})")
        else:
            checks_passed.append(f"[C] Velocity callout should appear at the end after all sections (last section paragraph at {backlog_paragraph_idx}, callout at {velocity_callout_idx})")
    
        # 12. Validate velocity calculation (checked items * 3)
        # Based on success criteria: 1 checked item * 3 = 3 effort points
        velocity_block = page_blocks[velocity_callout_idx]
        velocity_content = velocity_block.get("content", "")
    
        # Check if it mentions "3 effort points" (since 1 checked item * 3 = 3)
        if "3" not in velocity_content:
            errors.append(f"[X] Velocity callout should calculate effort points as checked_items * 3 (expected 3 for 1 checked item), but content is: '{velocity_content}'")
        else:
            checks_passed.append(f"[C] Velocity callout should calculate effort points as checked_items * 3 (expected 3 for 1 checked item), but content is: '{velocity_content}'")
    
        # ALL requirements met!
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: create-engineering-metrics-dashboard-v2
# Description: Create comprehensive Engineering Metrics Dashboard page analyzing
# Bug Tracker, Q1 Goals, and Q2 Goals with structured metrics and JSON analytics
# =============================================================================
def _validate_agent_create_engineering_metrics_dashboard(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate creation of Engineering Metrics Dashboard page with:
    - Page exists as child of 'Engineering Wiki'
    - heading_1 '🎯 Engineering Metrics Dashboard'
    - heading_2 '📊 Q1-Q2 Performance Overview'
    - Yellow callout with heading_3 'Quarterly Objectives' containing exact Q1/Q2 completion stats
    - heading_2 '🐛 Bug Resolution Metrics' with bulletedList structure
    - Toggle '📈 Detailed Analytics' with JSON code block containing specific metrics
    
    Returns 1.0 only if ALL requirements are met, otherwise 0.0
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Find the 'Engineering Wiki' page
    try:
        engineering_wiki = _find_page_by_title(final_state_backend, "Engineering Wiki")
        if not engineering_wiki:
            errors.append("[X] Engineering Wiki page not found")
        else:
            checks_passed.append("[C] Engineering Wiki page found")
    
        # 2. Find the 'Engineering Metrics Dashboard' page
        dashboard_page = _find_page_by_title(final_state_backend, "Engineering Metrics Dashboard")
        if not dashboard_page:
            errors.append("[X] Engineering Metrics Dashboard page not found")
        else:
            checks_passed.append("[C] Engineering Metrics Dashboard page found")
    
        dashboard_id = dashboard_page.get("_id")
    
        # 3. Verify it's a child of Engineering Wiki
        if not _check_page_is_child_of(engineering_wiki, dashboard_page):
            errors.append("[X] Engineering Metrics Dashboard is not a child of Engineering Wiki")
        else:
            checks_passed.append("[C] Engineering Metrics Dashboard is a child of Engineering Wiki")
    
        # 4. Analyze Bug Tracker, Q1 Goals, Q2 Goals for metrics
        bug_tracker = _find_page_by_title(final_state_backend, "Bug Tracker")
        q1_goals = _find_page_by_title(final_state_backend, "Q1 Goals")
        q2_goals = _find_page_by_title(final_state_backend, "Q2 Goals")
    
        if not bug_tracker:
            errors.append("[X] Bug Tracker page not found for analysis")
        else:
            checks_passed.append("[C] Bug Tracker page found for analysis")
        if not q1_goals:
            errors.append("[X] Q1 Goals page not found for analysis")
        else:
            checks_passed.append("[C] Q1 Goals page found for analysis")
        if not q2_goals:
            errors.append("[X] Q2 Goals page not found for analysis")
        else:
            checks_passed.append("[C] Q2 Goals page found for analysis")
    
        # Get todo blocks for each page using query-level filtering
        bug_todos = _get_todo_blocks(final_state_backend, bug_tracker.get("_id"))
        q1_todos = _get_todo_blocks(final_state_backend, q1_goals.get("_id"))
        q2_todos = _get_todo_blocks(final_state_backend, q2_goals.get("_id"))
    
        # Count Q1 goals (total and completed)
        q1_total = len(q1_todos)
        q1_completed = sum(1 for b in q1_todos if b.get("properties", {}).get("checked", False))
        q1_percent = round((q1_completed / q1_total * 100), 1) if q1_total > 0 else 0
    
        # Count Q2 goals
        q2_total = len(q2_todos)
        q2_completed = sum(1 for b in q2_todos if b.get("properties", {}).get("checked", False))
        q2_percent = round((q2_completed / q2_total * 100), 1) if q2_total > 0 else 0
    
        # Count bug metrics
        total_bugs = len(bug_todos)
        resolved_bugs = sum(1 for b in bug_todos if b.get("properties", {}).get("checked", False))
        critical_bugs_open = sum(1 for b in bug_todos 
                                 if not b.get("properties", {}).get("checked", False)
                                 and "critical" in b.get("content", "").lower())
    
        # 5. Get all blocks for the dashboard page
        dashboard_blocks = _get_blocks_for_page(final_state_backend, dashboard_id)
    
        if len(dashboard_blocks) < 5:
            errors.append(f"[X] Dashboard needs multiple structured blocks, found {len(dashboard_blocks)}")
        else:
            checks_passed.append(f"[C] Dashboard needs multiple structured blocks, found {len(dashboard_blocks)}")
    
        # 6. Find required structural elements
        h1_dashboard_idx = -1
        h2_performance_idx = -1
        yellow_callout_idx = -1
        h2_bug_metrics_idx = -1
        toggle_analytics_idx = -1
        code_block_idx = -1
    
        for idx, block in enumerate(dashboard_blocks):
            block_type = block.get("type", "")
            block_content = block.get("content", "")
            block_properties = block.get("properties", {})
        
            # Find heading_1 '🎯 Engineering Metrics Dashboard'
            if block_type == "heading1" and "🎯" in block_content and "engineering metrics dashboard" in block_content.lower():
                h1_dashboard_idx = idx
        
            # Find heading_2 '📊 Q1-Q2 Performance Overview'
            if block_type == "heading2" and "📊" in block_content and "q1-q2 performance overview" in block_content.lower():
                h2_performance_idx = idx
        
            # Find yellow callout with Quarterly Objectives
            if block_type == "callout":
                bg_color = block_properties.get("backgroundColor", "") if isinstance(block_properties, dict) else ""
                if "yellow" in bg_color.lower():
                    content_lower = block_content.lower()
                    # Check for heading_3 'Quarterly Objectives' and Q1/Q2 completion stats
                    if "quarterly objectives" in content_lower and "q1:" in content_lower and "q2:" in content_lower:
                        # Verify it contains completion percentage format
                        if "completed" in content_lower and "%" in block_content:
                            yellow_callout_idx = idx
        
            # Find heading_2 '🐛 Bug Resolution Metrics'
            if block_type == "heading2" and "🐛" in block_content and "bug resolution metrics" in block_content.lower():
                h2_bug_metrics_idx = idx
        
            # Find toggle '📈 Detailed Analytics'
            if block_type == "toggle" and "📈" in block_content and "detailed analytics" in block_content.lower():
                toggle_analytics_idx = idx
        
            # Find code block with JSON (should be within or after toggle)
            if block_type == "code":
                code_lang = block_properties.get("language", "") if isinstance(block_properties, dict) else ""
                if "json" in code_lang.lower():
                    # Check for required fields in JSON
                    content_lower = block_content.lower()
                    if "avgresolutionrate" in content_lower and "criticalbugsopen" in content_lower and "quarterlyvelocity" in content_lower:
                        code_block_idx = idx
    
        # 7. Validate all structural elements exist
        if h1_dashboard_idx == -1:
            errors.append("[X] heading_1 '🎯 Engineering Metrics Dashboard' not found")
        else:
            checks_passed.append("[C] heading_1 '🎯 Engineering Metrics Dashboard' found")
    
        if h2_performance_idx == -1:
            errors.append("[X] heading_2 '📊 Q1-Q2 Performance Overview' not found")
        else:
            checks_passed.append("[C] heading_2 '📊 Q1-Q2 Performance Overview' found")
    
        if yellow_callout_idx == -1:
            errors.append("[X] Yellow callout with 'Quarterly Objectives' and Q1/Q2 completion stats not found")
        else:
            checks_passed.append("[C] Yellow callout with 'Quarterly Objectives' and Q1/Q2 completion stats found")
    
        # 8. Validate Yellow callout contains correct Q1/Q2 stats
        yellow_callout = dashboard_blocks[yellow_callout_idx]
        callout_content = yellow_callout.get("content", "")
    
        # Check for Q1 completion percentage (should be 2 of 3 = 66.7%)
        if str(q1_completed) not in callout_content or str(q1_total) not in callout_content:
            errors.append(f"[X] Yellow callout should show Q1: {q1_completed} of {q1_total} completed, but content is: '{callout_content[:100]}'")
        else:
            checks_passed.append(f"[C] Yellow callout should show Q1: {q1_completed} of {q1_total} completed, but content is: '{callout_content[:100]}'")
    
        # Check for Q2 completion percentage (should be 0 of 2 = 0%)
        if str(q2_completed) not in callout_content or str(q2_total) not in callout_content:
            errors.append(f"[X] Yellow callout should show Q2: {q2_completed} of {q2_total} completed, but content is: '{callout_content[:100]}'")
        else:
            checks_passed.append(f"[C] Yellow callout should show Q2: {q2_completed} of {q2_total} completed, but content is: '{callout_content[:100]}'")
    
        if h2_bug_metrics_idx == -1:
            errors.append("[X] heading_2 '🐛 Bug Resolution Metrics' not found")
        else:
            checks_passed.append("[C] heading_2 '🐛 Bug Resolution Metrics' found")
    
        # 9. Validate bug metrics section has bulletedList blocks showing priority levels
        bug_section_has_bullets = False
        for idx in range(h2_bug_metrics_idx + 1, min(h2_bug_metrics_idx + 10, len(dashboard_blocks))):
            if idx < len(dashboard_blocks):
                block = dashboard_blocks[idx]
                if block.get("type") == "bulletedList":
                    bug_section_has_bullets = True
                    break
                # Stop if we hit another heading
                if block.get("type", "").startswith("heading"):
                    break
    
        if not bug_section_has_bullets:
            errors.append("[X] Bug Resolution Metrics section should contain bulletedList blocks showing priority levels")
        else:
            checks_passed.append("[C] Bug Resolution Metrics section should contain bulletedList blocks showing priority levels")
    
        if toggle_analytics_idx == -1:
            errors.append("[X] Toggle block '📈 Detailed Analytics' not found")
        else:
            checks_passed.append("[C] Toggle block '📈 Detailed Analytics' found")
    
        if code_block_idx == -1:
            errors.append("[X] Code block with language: json containing avgResolutionRate, criticalBugsOpen, quarterlyVelocity not found")
        else:
            checks_passed.append("[C] Code block with language: json containing avgResolutionRate, criticalBugsOpen, quarterlyVelocity found")
    
        # 10. Validate JSON code block contains correct metrics
        code_block = dashboard_blocks[code_block_idx]
        code_content = code_block.get("content", "")
    
        # Calculate expected values
        avg_resolution_rate = round(resolved_bugs / total_bugs, 1) if total_bugs > 0 else 0.0
        quarterly_velocity = q1_completed + q2_completed
    
        # Check if values are present in JSON (allow some flexibility in exact format)
        if str(avg_resolution_rate) not in code_content and f"{avg_resolution_rate:.1f}" not in code_content:
            errors.append(f"[X] JSON code block should contain avgResolutionRate: {avg_resolution_rate}, but content is: '{code_content[:100]}'")
        else:
            checks_passed.append(f"[C] JSON code block should contain avgResolutionRate: {avg_resolution_rate}, but content is: '{code_content[:100]}'")
    
        if str(critical_bugs_open) not in code_content:
            errors.append(f"[X] JSON code block should contain criticalBugsOpen: {critical_bugs_open}, but content is: '{code_content[:100]}'")
        else:
            checks_passed.append(f"[C] JSON code block should contain criticalBugsOpen: {critical_bugs_open}, but content is: '{code_content[:100]}'")
    
        if str(quarterly_velocity) not in code_content:
            errors.append(f"[X] JSON code block should contain quarterlyVelocity: {quarterly_velocity}, but content is: '{code_content[:100]}'")
        else:
            checks_passed.append(f"[C] JSON code block should contain quarterlyVelocity: {quarterly_velocity}, but content is: '{code_content[:100]}'")
    
        # 11. Validate structure order
        if not (h1_dashboard_idx < h2_performance_idx < yellow_callout_idx < h2_bug_metrics_idx < toggle_analytics_idx):
            errors.append(f"[X] Blocks not in correct order: h1({h1_dashboard_idx}) < h2_performance({h2_performance_idx}) < callout({yellow_callout_idx}) < h2_bug({h2_bug_metrics_idx}) < toggle({toggle_analytics_idx})")
        else:
            checks_passed.append(f"[C] Blocks in correct order: h1({h1_dashboard_idx}) < h2_performance({h2_performance_idx}) < callout({yellow_callout_idx}) < h2_bug({h2_bug_metrics_idx}) < toggle({toggle_analytics_idx})")
    
        # ALL requirements met!
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: create-q1-sprint-analysis-v2
# Description: Create Q1 2024 Sprint Analysis page analyzing all sub-pages of
# Meeting Notes, counting todos and completion rates with blue callout
# =============================================================================
def _validate_agent_create_q1_sprint_analysis(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate creation of Q1 2024 Sprint Analysis page with:
    - Page exists as child of 'Meeting Notes'
    - heading_1 '📊 Q1 2024 Sprint Analysis'
    - heading_2 '📈 Task Completion Overview'
    - Paragraphs showing total tasks and overall completion rate
    - heading_3 for each meeting page with task counts
    - Blue callout at end with today's date
    
    Returns 1.0 only if ALL requirements are met, otherwise 0.0
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Find the 'Meeting Notes' page
    try:
        meeting_notes_pages = _get_pages_by_filter(backend, {"title": "Meeting Notes"})
        if not meeting_notes_pages:
            errors.append("[X] Meeting Notes page not found")
        else:
            checks_passed.append("[C] Meeting Notes page found")
    
        meeting_notes = meeting_notes_pages[0]
        meeting_notes_id = meeting_notes.get("_id")
    
        # 2. Find the 'Q1 2024 Sprint Analysis' page
        analysis_pages = _get_pages_by_filter(backend, {"title": "Q1 2024 Sprint Analysis"})
        if not analysis_pages:
            errors.append("[X] Q1 2024 Sprint Analysis page not found")
        else:
            checks_passed.append("[C] Q1 2024 Sprint Analysis page found")
    
        analysis_page = analysis_pages[0]
        analysis_id = analysis_page.get("_id")
    
        # 3. Verify it's a child of Meeting Notes
        if analysis_page.get("parentId") != meeting_notes_id:
            errors.append("[X] Q1 2024 Sprint Analysis is not a child of Meeting Notes")
        else:
            checks_passed.append("[C] Q1 2024 Sprint Analysis is a child of Meeting Notes")
    
        # 4. Get all sub-pages of Meeting Notes
        meeting_subpages = _get_pages_by_filter(backend, {"parentId": meeting_notes_id})
    
        # Filter out the analysis page itself
        meeting_subpages = [p for p in meeting_subpages if p.get("_id") != analysis_id]
    
        if len(meeting_subpages) == 0:
            errors.append("[X] No sub-pages found under Meeting Notes to analyze")
        else:
            checks_passed.append("[C] sub-pages found under Meeting Notes to analyze")
    
        # 5. Analyze each meeting sub-page for todo counts
        total_todos_all_meetings = 0
        total_completed_all_meetings = 0
        meeting_stats = []
    
        for subpage in meeting_subpages:
            subpage_id = subpage.get("_id")
            subpage_title = subpage.get("title", "Untitled")
            subpage_blocks = _get_blocks_by_filter(backend, {"pageId": subpage_id})
        
            total_todos = sum(1 for b in subpage_blocks if b.get("type") == "todo")
            completed_todos = sum(1 for b in subpage_blocks if b.get("type") == "todo" and b.get("properties", {}).get("checked", False))
        
            if total_todos > 0:
                total_todos_all_meetings += total_todos
                total_completed_all_meetings += completed_todos
                meeting_stats.append({
                    "title": subpage_title,
                    "total": total_todos,
                    "completed": completed_todos
                })
    
        overall_percent = round((total_completed_all_meetings / total_todos_all_meetings * 100), 1) if total_todos_all_meetings > 0 else 0
    
        # 6. Get all blocks for the analysis page
        analysis_blocks = _get_blocks_by_filter(backend, {"pageId": analysis_id})
    
        if len(analysis_blocks) < 4:
            errors.append(f"[X] Analysis page needs multiple structured blocks, found {len(analysis_blocks)}")
        else:
            checks_passed.append(f"[C] Analysis page needs multiple structured blocks, found {len(analysis_blocks)}")
    
        # 7. Find required structural elements
        h1_analysis_idx = -1
        h2_overview_idx = -1
        para_total_tasks_idx = -1
        para_completion_rate_idx = -1
        blue_callout_idx = -1
        meeting_h3_indices = []
    
        for idx, block in enumerate(analysis_blocks):
            block_type = block.get("type", "")
            block_content = block.get("content", "")
            block_properties = block.get("properties", {})
        
            # Find heading_1 '📊 Q1 2024 Sprint Analysis'
            if block_type == "heading1" and "📊" in block_content and "q1 2024 sprint analysis" in block_content.lower():
                h1_analysis_idx = idx
        
            # Find heading_2 '📈 Task Completion Overview'
            if block_type == "heading2" and "📈" in block_content and "task completion overview" in block_content.lower():
                h2_overview_idx = idx
        
            # Find paragraph with total tasks
            if block_type == "paragraph" and "total tasks across all meetings:" in block_content.lower():
                if str(total_todos_all_meetings) in block_content:
                    para_total_tasks_idx = idx
        
            # Find paragraph with overall completion rate
            if block_type == "paragraph" and "overall completion rate:" in block_content.lower():
                if "%" in block_content:
                    para_completion_rate_idx = idx
        
            # Find heading_3 blocks for each meeting (should contain 📅 and meeting title)
            if block_type == "heading3" and "📅" in block_content:
                # Check if it matches any meeting title
                for stat in meeting_stats:
                    if stat["title"].lower() in block_content.lower():
                        meeting_h3_indices.append(idx)
                        break
        
            # Find blue callout at end with today's date
            if block_type == "callout":
                bg_color = block_properties.get("backgroundColor", "") if isinstance(block_properties, dict) else ""
                if "blue" in bg_color.lower():
                    content_lower = block_content.lower()
                    if "generated on" in content_lower:
                        blue_callout_idx = idx
    
        # 8. Validate all structural elements exist
        if h1_analysis_idx == -1:
            errors.append("[X] heading_1 '📊 Q1 2024 Sprint Analysis' not found")
        else:
            checks_passed.append("[C] heading_1 '📊 Q1 2024 Sprint Analysis' found")
    
        if h2_overview_idx == -1:
            errors.append("[X] heading_2 '📈 Task Completion Overview' not found")
        else:
            checks_passed.append("[C] heading_2 '📈 Task Completion Overview' found")
    
        if para_total_tasks_idx == -1:
            errors.append(f"[X] Paragraph with 'Total tasks across all meetings: {total_todos_all_meetings}' not found")
        else:
            checks_passed.append(f"[C] Paragraph with 'Total tasks across all meetings: {total_todos_all_meetings}' found")
    
        if para_completion_rate_idx == -1:
            errors.append("[X] Paragraph with 'Overall completion rate: [PERCENTAGE]%' not found")
        else:
            checks_passed.append("[C] Paragraph with 'Overall completion rate: [PERCENTAGE]%' found")
    
        # Verify completion rate percentage is correct
        completion_para = analysis_blocks[para_completion_rate_idx]
        completion_content = completion_para.get("content", "")
        # Allow some flexibility in percentage format (e.g., 40%, 40.0%)
        if not (str(int(overall_percent)) in completion_content or f"{overall_percent:.1f}" in completion_content):
            errors.append(f"[X] Completion rate percentage should be {overall_percent}%, but paragraph content is: '{completion_content}'")
        else:
            checks_passed.append(f"[C] Completion rate percentage should be {overall_percent}%, but paragraph content is: '{completion_content}'")
    
        # 9. Validate each meeting has its own heading_3 section with task counts
        if len(meeting_h3_indices) < len(meeting_stats):
            errors.append(f"[X] Expected heading_3 sections for {len(meeting_stats)} meetings, found {len(meeting_h3_indices)}")
        else:
            checks_passed.append(f"[C] Expected heading_3 sections for {len(meeting_stats)} meetings, found {len(meeting_h3_indices)}")
    
        # Validate that after each meeting heading, there are bulletedList items with task counts
        for h3_idx in meeting_h3_indices:
            has_bulleted_list_after = False
            for check_idx in range(h3_idx + 1, min(h3_idx + 5, len(analysis_blocks))):
                block = analysis_blocks[check_idx]
                if block.get("type") == "bulletedList":
                    has_bulleted_list_after = True
                    break
                if block.get("type", "").startswith("heading"):
                    break
        
            if not has_bulleted_list_after:
                errors.append(f"[X] Meeting heading_3 at idx {h3_idx} should be followed by bulletedList items with task counts")
            else:
                checks_passed.append(f"[C] Meeting heading_3 at idx {h3_idx} should be followed by bulletedList items with task counts")
    
        if blue_callout_idx == -1:
            errors.append("[X] Blue callout with 'Generated on [TODAY'S DATE]' not found at end of page")
        else:
            checks_passed.append("[C] Blue callout with 'Generated on [TODAY'S DATE]' found at end of page")
    
        # 10. Validate structure order
        if not (h1_analysis_idx < h2_overview_idx < para_total_tasks_idx < para_completion_rate_idx):
            errors.append(f"[X] Blocks not in correct order: h1({h1_analysis_idx}) < h2({h2_overview_idx}) < para_total({para_total_tasks_idx}) < para_completion({para_completion_rate_idx})")
        else:
            checks_passed.append(f"[C] Blocks in correct order: h1({h1_analysis_idx}) < h2({h2_overview_idx}) < para_total({para_total_tasks_idx}) < para_completion({para_completion_rate_idx})")
    
        # Validate callout is at or near the end
        if blue_callout_idx < max(meeting_h3_indices) if meeting_h3_indices else 0:
            errors.append(f"[X] Blue callout should be at the end after all meeting sections, found at idx {blue_callout_idx}")
        else:
            checks_passed.append(f"[C] Blue callout should be at the end after all meeting sections, found at idx {blue_callout_idx}")
    
        # ALL requirements met!
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: add-high-priority-bug-section-v2
# Description: Insert new High Priority section in Bug Tracker between Critical
# and Medium Priority sections with specific todos, divider, and statistics callout
# =============================================================================
def _validate_agent_add_high_priority_bug_section(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate addition of High Priority section to Bug Tracker with:
    - heading_2 'High Priority' positioned between 'Critical Bugs' and 'Medium Priority'
    - Exactly 3 unchecked todos with specific text and 🔴 prefix
    - Divider block after todos
    - Blue callout at end of page with 📊 icon and bug statistics
    
    Returns 1.0 only if ALL requirements are met, otherwise 0.0
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Find the 'Bug Tracker' page
    try:
        bug_tracker_pages = _get_pages_by_filter(backend, {"title": "Bug Tracker"})
        if not bug_tracker_pages:
            errors.append("[X] Bug Tracker page not found")
        else:
            checks_passed.append("[C] Bug Tracker page found")
    
        bug_tracker = bug_tracker_pages[0]
        bug_tracker_id = bug_tracker.get("_id")
    
        # 2. Get all blocks for Bug Tracker page
        bug_blocks = _get_blocks_by_filter(backend, {"pageId": bug_tracker_id})
    
        if len(bug_blocks) < 5:
            errors.append(f"[X] Bug Tracker needs sufficient blocks for new section, found {len(bug_blocks)}")
        else:
            checks_passed.append(f"[C] Bug Tracker needs sufficient blocks for new section, found {len(bug_blocks)}")
    
        # 3. Find key structural elements
        critical_heading_idx = -1
        high_priority_heading_idx = -1
        medium_priority_heading_idx = -1
        high_priority_todos = []
        divider_after_high_idx = -1
        stats_callout_idx = -1
    
        # Expected todo texts
        expected_todos = [
            "🔴 Fix memory leak in block renderer",
            "🔴 Resolve race condition in real-time sync",
            "🔴 Handle edge case in permission validation"
        ]
    
        for idx, block in enumerate(bug_blocks):
            block_type = block.get("type", "")
            block_content = block.get("content", "")
            block_properties = block.get("properties", {})
        
            # Find Critical Bugs heading
            if block_type in ["heading1", "heading2"] and "critical" in block_content.lower() and ("bugs" in block_content.lower() or "priority" in block_content.lower()):
                critical_heading_idx = idx
        
            # Find High Priority heading
            if block_type == "heading2" and "high priority" in block_content.lower() and "critical" not in block_content.lower():
                high_priority_heading_idx = idx
        
            # Find Medium Priority heading
            if block_type in ["heading2", "heading3"] and "medium" in block_content.lower() and "priority" in block_content.lower():
                medium_priority_heading_idx = idx
        
            # Find the 3 specific high priority todos
            if block_type == "todo":
                for expected_todo in expected_todos:
                    if expected_todo.strip() in block_content.strip():
                        is_checked = block_properties.get("checked", False) if isinstance(block_properties, dict) else False
                        high_priority_todos.append({
                            "idx": idx,
                            "text": block_content.strip(),
                            "checked": is_checked,
                            "expected": expected_todo
                        })
                        break
        
            # Find divider after High Priority section
            if block_type == "divider":
                # Check if this divider is after the High Priority heading
                if high_priority_heading_idx != -1 and idx > high_priority_heading_idx:
                    # Check if it's before Medium Priority or is the first divider after High Priority
                    if medium_priority_heading_idx == -1 or idx < medium_priority_heading_idx:
                        if divider_after_high_idx == -1:
                            divider_after_high_idx = idx
        
            # Find statistics callout at end
            if block_type == "callout":
                callout_props = block.get("properties", {})
                bg_color = callout_props.get("backgroundColor", "") if isinstance(callout_props, dict) else ""
                icon = callout_props.get("icon", "") if isinstance(callout_props, dict) else ""
            
                if "blue" in bg_color.lower() and "📊" in icon:
                    content_lower = block_content.lower()
                    if "bug statistics:" in content_lower and "total bugs tracked:" in content_lower:
                        stats_callout_idx = idx
    
        # 4. Validate Critical Bugs heading exists
        if critical_heading_idx == -1:
            errors.append("[X] Critical Bugs heading not found in Bug Tracker")
        else:
            checks_passed.append("[C] Critical Bugs heading found in Bug Tracker")
    
        # 5. Validate High Priority heading exists
        if high_priority_heading_idx == -1:
            errors.append("[X] High Priority heading_2 not found")
        else:
            checks_passed.append("[C] High Priority heading_2 found")
    
        # 6. Validate Medium Priority heading exists
        if medium_priority_heading_idx == -1:
            errors.append("[X] Medium Priority heading not found in Bug Tracker")
        else:
            checks_passed.append("[C] Medium Priority heading found in Bug Tracker")
    
        # 7. Validate High Priority is positioned between Critical and Medium
        if not (critical_heading_idx < high_priority_heading_idx < medium_priority_heading_idx):
            errors.append(f"[X] High Priority heading must be positioned between Critical Bugs (idx {critical_heading_idx}) and Medium Priority (idx {medium_priority_heading_idx}), found at idx {high_priority_heading_idx}")
        else:
            checks_passed.append(f"[C] High Priority heading must be positioned between Critical Bugs (idx {critical_heading_idx}) and Medium Priority (idx {medium_priority_heading_idx}), found at idx {high_priority_heading_idx}")
    
        # 8. Validate exactly 3 high priority todos were found
        if len(high_priority_todos) != 3:
            missing = [exp for exp in expected_todos if not any(ft["expected"] == exp for ft in high_priority_todos)]
            errors.append(f"[X] Expected 3 high priority todos, found {len(high_priority_todos)}. Missing: {missing}")
        else:
            checks_passed.append(f"[C] Found 3 high priority todos as expected")
    
        # 9. Validate all todos are unchecked
        checked_todos = [t for t in high_priority_todos if t["checked"]]
        if checked_todos:
            errors.append(f"[X] All high priority todos should be unchecked, but {len(checked_todos)} are checked")
        else:
            checks_passed.append(f"[C] All high priority todos should be unchecked, but {len(checked_todos)} are checked")
    
        # 10. Validate all todos have 🔴 prefix
        for todo in high_priority_todos:
            if "🔴" not in todo["text"]:
                errors.append(f"[X] Todo '{todo['text']}' should have 🔴 prefix")
            else:
                checks_passed.append(f"[C] Todo '{todo['text']}' should have 🔴 prefix")
    
        # 11. Validate todos are positioned after High Priority heading and before Medium Priority
        for todo in high_priority_todos:
            if not (high_priority_heading_idx < todo["idx"] < medium_priority_heading_idx):
                errors.append(f"[X] Todo at idx {todo['idx']} should be between High Priority heading (idx {high_priority_heading_idx}) and Medium Priority heading (idx {medium_priority_heading_idx})")
            else:
                checks_passed.append(f"[C] Todo at idx {todo['idx']} should be between High Priority heading (idx {high_priority_heading_idx}) and Medium Priority heading (idx {medium_priority_heading_idx})")
    
        # 12. Validate divider exists after the todos
        if divider_after_high_idx == -1:
            errors.append("[X] Divider block not found after High Priority todos")
        else:
            checks_passed.append("[C] Divider block found after High Priority todos")
    
        # Verify divider is after todos but before Medium Priority
        max_todo_idx = max(t["idx"] for t in high_priority_todos)
        if not (max_todo_idx < divider_after_high_idx < medium_priority_heading_idx):
            errors.append(f"[X] Divider should be after todos (max idx {max_todo_idx}) but before Medium Priority (idx {medium_priority_heading_idx}), found at idx {divider_after_high_idx}")
        else:
            checks_passed.append(f"[C] Divider should be after todos (max idx {max_todo_idx}) but before Medium Priority (idx {medium_priority_heading_idx}), found at idx {divider_after_high_idx}")
    
        # 13. Validate statistics callout exists at end
        if stats_callout_idx == -1:
            errors.append("[X] Statistics callout with blue background and 📊 icon not found at end of page")
        else:
            checks_passed.append("[C] Statistics callout with blue background and 📊 icon found at end of page")
    
        # 14. Count all todos in Bug Tracker for statistics validation
        all_bug_todos = [b for b in bug_blocks if b.get("type") == "todo"]
        total_bugs = len(all_bug_todos)
        resolved_bugs = sum(1 for b in all_bug_todos if b.get("properties", {}).get("checked", False))
        pending_bugs = total_bugs - resolved_bugs
        resolved_percent = round((resolved_bugs / total_bugs * 100), 1) if total_bugs > 0 else 0
    
        # 15. Validate statistics callout contains correct counts
        stats_callout = bug_blocks[stats_callout_idx]
        stats_content = stats_callout.get("content", "")
    
        if str(total_bugs) not in stats_content:
            errors.append(f"[X] Statistics callout should show Total bugs tracked: {total_bugs}, but content is: '{stats_content[:100]}'")
        else:
            checks_passed.append(f"[C] Statistics callout should show Total bugs tracked: {total_bugs}, but content is: '{stats_content[:100]}'")
    
        if str(resolved_bugs) not in stats_content:
            errors.append(f"[X] Statistics callout should show Resolved: {resolved_bugs}, but content is: '{stats_content[:100]}'")
        else:
            checks_passed.append(f"[C] Statistics callout should show Resolved: {resolved_bugs}, but content is: '{stats_content[:100]}'")
    
        if str(pending_bugs) not in stats_content:
            errors.append(f"[X] Statistics callout should show Pending: {pending_bugs}, but content is: '{stats_content[:100]}'")
        else:
            checks_passed.append(f"[C] Statistics callout should show Pending: {pending_bugs}, but content is: '{stats_content[:100]}'")
    
        # Check for percentage (allow some flexibility in format)
        if not (str(int(resolved_percent)) in stats_content or f"{resolved_percent:.1f}" in stats_content):
            errors.append(f"[X] Statistics callout should show resolution percentage {resolved_percent}%, but content is: '{stats_content[:100]}'")
        else:
            checks_passed.append(f"[C] Statistics callout should show resolution percentage {resolved_percent}%, but content is: '{stats_content[:100]}'")
    
        # ALL requirements met!
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: add-time-allocation-to-standup-v2
# Description: Insert Time Allocation section in Weekly Standup Template between
# 'What I plan to do next week' and 'Blockers' with blue callout and task stats
# =============================================================================
def _validate_agent_add_time_allocation_to_standup(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate addition of Time Allocation section to Weekly Standup Template with:
    - heading_2 '⏱️ Time Allocation This Week' between 'What I plan to do next week' and 'Blockers'
    - Blue callout with no icon containing heading_3 'Hours by Category'
    - Numbered list within callout with 4 items showing hours
    - Paragraph showing total hours (TODO: should check for bold formatting in future)
    - Paragraph showing task completion stats (TODO: should check for italic formatting in future)
    
    Returns 1.0 only if ALL requirements are met, otherwise 0.0
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Find the 'Weekly Standup Template' page
    try:
        standup_page = _find_page_by_title(final_state_backend, "Weekly Standup Template")
        if not standup_page:
            errors.append("[X] Weekly Standup Template page not found")
        else:
            checks_passed.append("[C] Weekly Standup Template page found")
    
        standup_id = standup_page.get("_id")
    
        # 2. Get all blocks for Weekly Standup Template page
        standup_blocks = _get_blocks_for_page(final_state_backend, standup_id)
    
        if len(standup_blocks) < 5:
            errors.append(f"[X] Weekly Standup Template needs sufficient blocks, found {len(standup_blocks)}")
        else:
            checks_passed.append(f"[C] Weekly Standup Template needs sufficient blocks, found {len(standup_blocks)}")
    
        # 3. Count all todos on the page for statistics
        all_todos = [b for b in standup_blocks if b.get("type") == "todo"]
        total_todos = len(all_todos)
        checked_todos = sum(1 for b in all_todos if b.get("properties", {}).get("checked", False))
        completion_percent = round((checked_todos / total_todos * 100), 1) if total_todos > 0 else 0
    
        # 4. Find key structural elements
        plan_next_week_idx = -1
        time_allocation_heading_idx = -1
        blockers_heading_idx = -1
        blue_callout_idx = -1
        hours_h3_idx = -1
        numbered_list_indices = []
        # TODO: Re-enable bold check when formatting is ready
        total_hours_para_idx = -1
        # TODO: Re-enable italic check when formatting is ready
        task_completion_para_idx = -1
    
        # Expected numbered list items
        expected_hours = [
            ("Feature development", "24"),
            ("Code reviews", "8"),
            ("Meetings", "6"),
            ("Documentation", "2")
        ]
    
        found_hours = []
    
        for idx, block in enumerate(standup_blocks):
            block_type = block.get("type", "")
            block_content = block.get("content", "")
            block_properties = block.get("properties", {})
        
            # Find 'What I plan to do next week' section
            if "what i plan to do next week" in block_content.lower():
                plan_next_week_idx = idx
        
            # Find Time Allocation heading
            if block_type == "heading2" and "⏱️" in block_content and "time allocation this week" in block_content.lower():
                time_allocation_heading_idx = idx
        
            # Find Blockers heading
            if block_type in ["heading1", "heading2"] and "blockers" in block_content.lower():
                blockers_heading_idx = idx
        
            # Find blue callout with no icon
            if block_type == "callout":
                callout_props = block.get("properties", {})
                bg_color = callout_props.get("backgroundColor", "") if isinstance(callout_props, dict) else ""
                icon = callout_props.get("icon", "") if isinstance(callout_props, dict) else ""
            
                # Blue background, no icon (empty string or None)
                if "blue" in bg_color.lower():
                    # Check if it contains Hours by Category
                    if "hours by category" in block_content.lower():
                        blue_callout_idx = idx
                        # Look for heading_3 within the callout content
                        if "hours by category" in block_content.lower():
                            hours_h3_idx = idx  # Simplified: treating callout as container
        
            # Find numbered list items
            if block_type == "numberedList":
                for category, hours in expected_hours:
                    if category.lower() in block_content.lower() and hours in block_content:
                        numbered_list_indices.append(idx)
                        found_hours.append({
                            "idx": idx,
                            "category": category,
                            "hours": hours,
                            "content": block_content
                        })
                        break
        
            # Find paragraph with total hours
            # TODO: Re-enable bold formatting check when ready - should verify bold formatting
            if block_type == "paragraph":
                # RELAXED: Bold formatting check temporarily disabled
                # has_bold = "**" in block_content or (isinstance(block_properties, dict) and block_properties.get("bold", False))
                if "total productive hours: 40" in block_content.lower():
                    total_hours_para_idx = idx
        
            # Find paragraph with task completion
            # TODO: Re-enable italic formatting check when ready - should verify italic formatting
            if block_type == "paragraph":
                # RELAXED: Italic formatting check temporarily disabled
                # has_italic = "*" in block_content or (isinstance(block_properties, dict) and block_properties.get("italic", False))
                content_lower = block_content.lower()
                if "tasks completed:" in content_lower and "completion rate" in content_lower:
                    # Check if it has the correct stats
                    if str(checked_todos) in block_content and str(total_todos) in block_content:
                        task_completion_para_idx = idx
    
        # 5. Validate 'What I plan to do next week' section exists
        if plan_next_week_idx == -1:
            errors.append("[X] 'What I plan to do next week' section not found")
        else:
            checks_passed.append("[C] 'What I plan to do next week' section found")
    
        # 6. Validate Time Allocation heading exists
        if time_allocation_heading_idx == -1:
            errors.append("[X] heading_2 '⏱️ Time Allocation This Week' not found")
        else:
            checks_passed.append("[C] heading_2 '⏱️ Time Allocation This Week' found")
    
        # 7. Validate Blockers heading exists
        if blockers_heading_idx == -1:
            errors.append("[X] 'Blockers' heading not found")
        else:
            checks_passed.append("[C] 'Blockers' heading found")
    
        # 8. Validate Time Allocation is positioned between plan next week and Blockers
        if not (plan_next_week_idx < time_allocation_heading_idx < blockers_heading_idx):
            errors.append(f"[X] Time Allocation heading must be positioned after 'What I plan to do next week' (idx {plan_next_week_idx}) and before 'Blockers' (idx {blockers_heading_idx}), found at idx {time_allocation_heading_idx}")
        else:
            checks_passed.append(f"[C] Time Allocation heading must be positioned after 'What I plan to do next week' (idx {plan_next_week_idx}) and before 'Blockers' (idx {blockers_heading_idx}), found at idx {time_allocation_heading_idx}")
    
        # 9. Validate blue callout exists
        if blue_callout_idx == -1:
            errors.append("[X] Blue callout with 'Hours by Category' not found")
        else:
            checks_passed.append("[C] Blue callout with 'Hours by Category' found")
    
        # 10. Validate callout is after Time Allocation heading
        if blue_callout_idx <= time_allocation_heading_idx:
            errors.append(f"[X] Blue callout should be after Time Allocation heading (idx {time_allocation_heading_idx}), found at idx {blue_callout_idx}")
        else:
            checks_passed.append(f"[C] Blue callout should be after Time Allocation heading (idx {time_allocation_heading_idx}), found at idx {blue_callout_idx}")
    
        # 11. Validate all 4 numbered list items were found
        if len(found_hours) != 4:
            missing = [f"{cat} ({hrs} hours)" for cat, hrs in expected_hours if not any(fh["category"] == cat for fh in found_hours)]
            errors.append(f"[X] Expected 4 numbered list items with hours, found {len(found_hours)}. Missing: {missing}")
        else:
            checks_passed.append(f"[C] Found 4 numbered list items with hours as expected")
    
        # 12. Validate numbered list items are in correct order
        # Check they appear after the callout
        for hour_item in found_hours:
            if hour_item["idx"] < blue_callout_idx:
                errors.append(f"[X] Numbered list items should be within or after blue callout (idx {blue_callout_idx}), found item at idx {hour_item['idx']}")
            else:
                checks_passed.append(f"[C] Numbered list items should be within or after blue callout (idx {blue_callout_idx}), found item at idx {hour_item['idx']}")
    
        # 13. Validate paragraph with total hours exists
        # TODO: Re-enable bold check when formatting is ready - should verify bold formatting
        if total_hours_para_idx == -1:
            errors.append("[X] Paragraph with 'Total productive hours: 40' not found")
        else:
            checks_passed.append("[C] Paragraph with 'Total productive hours: 40' found")
    
        # 14. Validate total hours paragraph is after callout but before Blockers
        if not (blue_callout_idx < total_hours_para_idx < blockers_heading_idx):
            errors.append(f"[X] Total hours paragraph should be after blue callout (idx {blue_callout_idx}) but before Blockers (idx {blockers_heading_idx}), found at idx {total_hours_para_idx}")
        else:
            checks_passed.append(f"[C] Total hours paragraph should be after blue callout (idx {blue_callout_idx}) but before Blockers (idx {blockers_heading_idx}), found at idx {total_hours_para_idx}")
    
        # 15. Validate paragraph with task completion exists
        # TODO: Re-enable italic check when formatting is ready - should verify italic formatting
        if task_completion_para_idx == -1:
            errors.append(f"[X] Paragraph with task completion stats (Tasks completed: {checked_todos} of {total_todos}) not found")
        else:
            checks_passed.append(f"[C] Paragraph with task completion stats (Tasks completed: {checked_todos} of {total_todos}) found")
    
        # 16. Validate task completion paragraph is after total hours paragraph
        if task_completion_para_idx <= total_hours_para_idx:
            errors.append(f"[X] Task completion paragraph should be after total hours paragraph (idx {total_hours_para_idx}), found at idx {task_completion_para_idx}")
        else:
            checks_passed.append(f"[C] Task completion paragraph should be after total hours paragraph (idx {total_hours_para_idx}), found at idx {task_completion_para_idx}")
    
        # 17. Validate completion rate in task completion paragraph
        task_completion_para = standup_blocks[task_completion_para_idx]
        task_completion_content = task_completion_para.get("content", "")
    
        if not (str(int(completion_percent)) in task_completion_content or f"{completion_percent:.1f}" in task_completion_content):
            errors.append(f"[X] Task completion paragraph should show completion rate {completion_percent}%, but content is: '{task_completion_content}'")
        else:
            checks_passed.append(f"[C] Task completion paragraph should show completion rate {completion_percent}%, but content is: '{task_completion_content}'")
    
        # ALL requirements met!
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: add-acceptance-criteria-section-v2
# Description: Insert Acceptance Criteria section in Comprehensive Product Requirements
# Document between User Stories and Technical Requirements with three-part structure
# =============================================================================
def _validate_agent_add_acceptance_criteria_section(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate addition of Acceptance Criteria section to Comprehensive Product Requirements Document with:
    - heading_2 '🎯 Acceptance Criteria' positioned between 'User Stories' and 'Technical Requirements'
    - Three-part structure matching pattern of other sections
    - Each part has heading_3, 2 paragraphs, and 3 bulletedList items with exact text
    - Divider block after all parts
    - Purple callout with heading_3 '✅ Validation Checklist' and summary stats
    
    Returns 1.0 only if ALL requirements are met, otherwise 0.0
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Find the 'Comprehensive Product Requirements Document' page
    try:
        prd_page = _find_page_by_title(final_state_backend, "Comprehensive Product Requirements Document")
        if not prd_page:
            errors.append("[X] Comprehensive Product Requirements Document page not found")
        else:
            checks_passed.append("[C] Comprehensive Product Requirements Document page found")
    
        prd_id = prd_page.get("_id")
    
        # 2. Get all blocks for the PRD page
        prd_blocks = _get_blocks_for_page(final_state_backend, prd_id)
    
        if len(prd_blocks) < 10:
            errors.append(f"[X] PRD needs sufficient blocks for new section, found {len(prd_blocks)}")
        else:
            checks_passed.append(f"[C] PRD needs sufficient blocks for new section, found {len(prd_blocks)}")
    
        # 3. Find key structural elements
        user_stories_heading_idx = -1
        acceptance_criteria_heading_idx = -1
        technical_requirements_heading_idx = -1
    
        # Three-part structure
        part1_h3_idx = -1
        part2_h3_idx = -1
        part3_h3_idx = -1
    
        part1_paragraphs = []
        part2_paragraphs = []
        part3_paragraphs = []
    
        part1_bullets = []
        part2_bullets = []
        part3_bullets = []
    
        divider_after_parts_idx = -1
        purple_callout_idx = -1
    
        for idx, block in enumerate(prd_blocks):
            block_type = block.get("type", "")
            block_content = block.get("content", "")
            block_properties = block.get("properties", {})
        
            # Find User Stories heading
            if block_type in ["heading1", "heading2"] and "user stories" in block_content.lower():
                user_stories_heading_idx = idx
        
            # Find Acceptance Criteria heading
            if block_type == "heading2" and "🎯" in block_content and "acceptance criteria" in block_content.lower():
                acceptance_criteria_heading_idx = idx
        
            # Find Technical Requirements heading
            if block_type in ["heading1", "heading2"] and "technical requirements" in block_content.lower():
                technical_requirements_heading_idx = idx
        
            # Find Part 1, 2, 3 headings
            if block_type == "heading3":
                if "acceptance criteria - part 1" in block_content.lower():
                    part1_h3_idx = idx
                elif "acceptance criteria - part 2" in block_content.lower():
                    part2_h3_idx = idx
                elif "acceptance criteria - part 3" in block_content.lower():
                    part3_h3_idx = idx
        
            # Collect paragraphs for each part
            if block_type == "paragraph":
                content_lower = block_content.lower()
                if "detailed acceptance criteria for part" in content_lower:
                    if part1_h3_idx != -1 and (part2_h3_idx == -1 or idx < part2_h3_idx):
                        if idx > part1_h3_idx:
                            part1_paragraphs.append(idx)
                    elif part2_h3_idx != -1 and (part3_h3_idx == -1 or idx < part3_h3_idx):
                        if idx > part2_h3_idx:
                            part2_paragraphs.append(idx)
                    elif part3_h3_idx != -1:
                        if idx > part3_h3_idx:
                            # Make sure we're still within the acceptance criteria section
                            if divider_after_parts_idx == -1 or idx < divider_after_parts_idx:
                                part3_paragraphs.append(idx)
        
            # Collect bulletedList items for each part
            if block_type == "bulletedList":
                content_lower = block_content.lower()
                if "key criterion" in content_lower and "acceptance" in content_lower:
                    # Determine which part this belongs to
                    if part1_h3_idx != -1 and (part2_h3_idx == -1 or idx < part2_h3_idx):
                        if idx > part1_h3_idx:
                            part1_bullets.append(idx)
                    elif part2_h3_idx != -1 and (part3_h3_idx == -1 or idx < part3_h3_idx):
                        if idx > part2_h3_idx:
                            part2_bullets.append(idx)
                    elif part3_h3_idx != -1:
                        if idx > part3_h3_idx:
                            if divider_after_parts_idx == -1 or idx < divider_after_parts_idx:
                                part3_bullets.append(idx)
        
            # Find divider after all parts
            if block_type == "divider":
                if part3_h3_idx != -1 and idx > part3_h3_idx:
                    if technical_requirements_heading_idx == -1 or idx < technical_requirements_heading_idx:
                        if divider_after_parts_idx == -1:
                            divider_after_parts_idx = idx
        
            # Find purple callout with validation checklist
            if block_type == "callout":
                callout_props = block.get("properties", {})
                bg_color = callout_props.get("backgroundColor", "") if isinstance(callout_props, dict) else ""
            
                if "purple" in bg_color.lower():
                    content_lower = block_content.lower()
                    if "✅" in block_content and "validation checklist" in content_lower:
                        if "total criteria sections: 3" in content_lower and "total criteria points: 9" in content_lower:
                            purple_callout_idx = idx
    
        # 4. Validate User Stories heading exists
        if user_stories_heading_idx == -1:
            errors.append("[X] User Stories heading not found in PRD")
        else:
            checks_passed.append("[C] User Stories heading found in PRD")
    
        # 5. Validate Acceptance Criteria heading exists
        if acceptance_criteria_heading_idx == -1:
            errors.append("[X] heading_2 '🎯 Acceptance Criteria' not found")
        else:
            checks_passed.append("[C] heading_2 '🎯 Acceptance Criteria' found")
    
        # 6. Validate Technical Requirements heading exists
        if technical_requirements_heading_idx == -1:
            errors.append("[X] Technical Requirements heading not found in PRD")
        else:
            checks_passed.append("[C] Technical Requirements heading found in PRD")
    
        # 7. Validate Acceptance Criteria is positioned between User Stories and Technical Requirements
        if not (user_stories_heading_idx < acceptance_criteria_heading_idx < technical_requirements_heading_idx):
            errors.append(f"[X] Acceptance Criteria heading must be positioned between User Stories (idx {user_stories_heading_idx}) and Technical Requirements (idx {technical_requirements_heading_idx}), found at idx {acceptance_criteria_heading_idx}")
        else:
            checks_passed.append(f"[C] Acceptance Criteria heading must be positioned between User Stories (idx {user_stories_heading_idx}) and Technical Requirements (idx {technical_requirements_heading_idx}), found at idx {acceptance_criteria_heading_idx}")
    
        # 8. Validate all three part headings exist
        if part1_h3_idx == -1:
            errors.append("[X] heading_3 'Acceptance Criteria - Part 1' not found")
        else:
            checks_passed.append("[C] heading_3 'Acceptance Criteria - Part 1' found")
    
        if part2_h3_idx == -1:
            errors.append("[X] heading_3 'Acceptance Criteria - Part 2' not found")
        else:
            checks_passed.append("[C] heading_3 'Acceptance Criteria - Part 2' found")
    
        if part3_h3_idx == -1:
            errors.append("[X] heading_3 'Acceptance Criteria - Part 3' not found")
        else:
            checks_passed.append("[C] heading_3 'Acceptance Criteria - Part 3' found")
    
        # 9. Validate parts are in correct order
        if not (part1_h3_idx < part2_h3_idx < part3_h3_idx):
            errors.append(f"[X] Part headings not in correct order: Part 1 (idx {part1_h3_idx}) < Part 2 (idx {part2_h3_idx}) < Part 3 (idx {part3_h3_idx})")
        else:
            checks_passed.append(f"[C] Part headings in correct order: Part 1 (idx {part1_h3_idx}) < Part 2 (idx {part2_h3_idx}) < Part 3 (idx {part3_h3_idx})")
    
        # 10. Validate each part has exactly 2 paragraphs
        if len(part1_paragraphs) < 2:
            errors.append(f"[X] Part 1 should have at least 2 paragraphs with acceptance criteria details, found {len(part1_paragraphs)}")
        else:
            checks_passed.append(f"[C] Part 1 should have at least 2 paragraphs with acceptance criteria details, found {len(part1_paragraphs)}")
    
        if len(part2_paragraphs) < 2:
            errors.append(f"[X] Part 2 should have at least 2 paragraphs with acceptance criteria details, found {len(part2_paragraphs)}")
        else:
            checks_passed.append(f"[C] Part 2 should have at least 2 paragraphs with acceptance criteria details, found {len(part2_paragraphs)}")
    
        if len(part3_paragraphs) < 2:
            errors.append(f"[X] Part 3 should have at least 2 paragraphs with acceptance criteria details, found {len(part3_paragraphs)}")
        else:
            checks_passed.append(f"[C] Part 3 should have at least 2 paragraphs with acceptance criteria details, found {len(part3_paragraphs)}")
    
        # 11. Validate each part has exactly 3 bulletedList items
        if len(part1_bullets) != 3:
            errors.append(f"[X] Part 1 should have exactly 3 bulletedList items with key criteria, found {len(part1_bullets)}")
        else:
            checks_passed.append(f"[C] Part 1 should have exactly 3 bulletedList items with key criteria, found {len(part1_bullets)}")
    
        if len(part2_bullets) != 3:
            errors.append(f"[X] Part 2 should have exactly 3 bulletedList items with key criteria, found {len(part2_bullets)}")
        else:
            checks_passed.append(f"[C] Part 2 should have exactly 3 bulletedList items with key criteria, found {len(part2_bullets)}")
    
        if len(part3_bullets) != 3:
            errors.append(f"[X] Part 3 should have exactly 3 bulletedList items with key criteria, found {len(part3_bullets)}")
        else:
            checks_passed.append(f"[C] Part 3 should have exactly 3 bulletedList items with key criteria, found {len(part3_bullets)}")
    
        # 12. Validate divider exists after all parts
        if divider_after_parts_idx == -1:
            errors.append("[X] Divider block not found after all three Acceptance Criteria parts")
        else:
            checks_passed.append("[C] Divider block found after all three Acceptance Criteria parts")
    
        # 13. Validate divider is after Part 3 but before Technical Requirements
        if not (part3_h3_idx < divider_after_parts_idx < technical_requirements_heading_idx):
            errors.append(f"[X] Divider should be after Part 3 (idx {part3_h3_idx}) but before Technical Requirements (idx {technical_requirements_heading_idx}), found at idx {divider_after_parts_idx}")
        else:
            checks_passed.append(f"[C] Divider should be after Part 3 (idx {part3_h3_idx}) but before Technical Requirements (idx {technical_requirements_heading_idx}), found at idx {divider_after_parts_idx}")
    
        # 14. Validate purple callout exists
        if purple_callout_idx == -1:
            errors.append("[X] Purple callout with '✅ Validation Checklist' and summary stats not found")
        else:
            checks_passed.append("[C] Purple callout with '✅ Validation Checklist' and summary stats found")
    
        # 15. Validate callout is after divider but before Technical Requirements
        if not (divider_after_parts_idx < purple_callout_idx < technical_requirements_heading_idx):
            errors.append(f"[X] Purple callout should be after divider (idx {divider_after_parts_idx}) but before Technical Requirements (idx {technical_requirements_heading_idx}), found at idx {purple_callout_idx}")
        else:
            checks_passed.append(f"[C] Purple callout should be after divider (idx {divider_after_parts_idx}) but before Technical Requirements (idx {technical_requirements_heading_idx}), found at idx {purple_callout_idx}")
    
        # ALL requirements met!
        total_criteria_points = len(part1_bullets) + len(part2_bullets) + len(part3_bullets)
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: add-remote-work-policy-to-handbook-v2
# Description: Insert a comprehensive Remote Work Policy section into the Company 
# Handbook page after existing policy content with specific formatting and structure
# =============================================================================
def _validate_agent_add_remote_work_policy_to_handbook(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate insertion of Remote Work Policy section with:
    - Section inserted after policy content but before next major heading
    - heading_2 '📐 Remote Work Policy' with exact emoji
    - Quote block with philosophical statement
    - heading_3 '🏠 Eligibility and Guidelines' with 4 numbered list items
    - heading_3 '💼 Equipment and Setup' with 3 bulleted list items
    - Divider at the end
    
    Returns 1.0 only if ALL requirements are met, otherwise 0.0
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Find the 'Company Handbook' page
    try:
        handbook_pages = _get_pages_by_filter(backend, {"title": "Company Handbook"})
        if not handbook_pages:
            errors.append("[X] Company Handbook page not found")
        else:
            checks_passed.append("[C] Company Handbook page found")
    
        handbook_page = handbook_pages[0]
        handbook_id = handbook_page.get("_id")
    
        # 2. Get all blocks for the handbook page
        handbook_blocks = _get_blocks_by_filter(backend, {"pageId": handbook_id})
    
        if len(handbook_blocks) < 10:
            errors.append(f"[X] Company Handbook needs more blocks for the new section, found {len(handbook_blocks)}")
        else:
            checks_passed.append(f"[C] Company Handbook needs more blocks for the new section, found {len(handbook_blocks)}")
    
        # 3. Find key sections and elements
        policy_content_idx = -1
        remote_work_heading_idx = -1
        quote_block_idx = -1
        eligibility_heading_idx = -1
        equipment_heading_idx = -1
        next_major_heading_idx = -1
        divider_idx = -1
    
        eligibility_numbered_items = []
        equipment_bulleted_items = []
    
        # First pass: find Remote Work Policy heading
        for idx, block in enumerate(handbook_blocks):
            block_type = block.get("type", "")
            block_content = block.get("content", "").lower()
            if block_type == "heading2" and "📐" in block.get("content", "") and "remote work policy" in block_content:
                remote_work_heading_idx = idx
                break
    
        for idx, block in enumerate(handbook_blocks):
            block_type = block.get("type", "")
            block_content = block.get("content", "").lower()
            block_properties = block.get("properties", {})
        
            # Find policy-related content (any block mentioning policy/procedure/guidelines)
            # Only look at blocks BEFORE the Remote Work Policy heading to avoid detecting our new content
            if any(term in block_content for term in ["policy", "procedure", "guidelines"]):
                if remote_work_heading_idx == -1 or idx < remote_work_heading_idx:
                    if policy_content_idx == -1 or idx > policy_content_idx:
                        # Track the last policy-related content before Remote Work Policy section
                        policy_content_idx = idx
        
            # Find Remote Work Policy heading (already found in first pass, but keep for consistency)
            if block_type == "heading2" and "📐" in block.get("content", "") and "remote work policy" in block_content:
                remote_work_heading_idx = idx
        
            # Find quote block with philosophical statement
            if block_type == "quote":
                quote_content = block.get("content", "")
                if "flexibility" in quote_content.lower() and "productivity" in quote_content.lower() and "trust" in quote_content.lower():
                    quote_block_idx = idx
        
            # Find Eligibility and Guidelines heading
            if block_type == "heading3" and "🏠" in block.get("content", "") and "eligibility and guidelines" in block_content:
                eligibility_heading_idx = idx
        
            # Find Equipment and Setup heading
            if block_type == "heading3" and "💼" in block.get("content", "") and "equipment and setup" in block_content:
                equipment_heading_idx = idx
        
            # Collect numbered list items for eligibility section
            if block_type == "numberedList":
                # Check if this is in the eligibility section
                if eligibility_heading_idx != -1 and idx > eligibility_heading_idx:
                    # Make sure we haven't reached equipment section yet
                    if equipment_heading_idx == -1 or idx < equipment_heading_idx:
                        if any(term in block_content for term in ["employees", "probation", "core hours", "timezone", "internet", "mbps", "meetings", "video"]):
                            eligibility_numbered_items.append(idx)
        
            # Collect bulleted list items for equipment section
            if block_type == "bulletedList":
                # Check if this is in the equipment section
                if equipment_heading_idx != -1 and idx > equipment_heading_idx:
                    if any(term in block_content for term in ["laptop", "software", "stipend", "office", "internet", "reimbursement"]):
                        equipment_bulleted_items.append(idx)
        
            # Find divider after the equipment section
            if block_type == "divider":
                if equipment_heading_idx != -1 and idx > equipment_heading_idx:
                    if divider_idx == -1:
                        divider_idx = idx
        
            # Find next major heading after Remote Work Policy section
            if remote_work_heading_idx != -1 and idx > remote_work_heading_idx:
                if block_type in ["heading1", "heading2"]:
                    # This is a major heading after our section
                    if "remote work" not in block_content:
                        if next_major_heading_idx == -1:
                            next_major_heading_idx = idx
    
        # 4. Validate Remote Work Policy heading exists
        if remote_work_heading_idx == -1:
            errors.append("[X] heading_2 '📐 Remote Work Policy' not found")
        else:
            checks_passed.append("[C] heading_2 '📐 Remote Work Policy' found")
    
        # 5. Validate Remote Work Policy is inserted after policy content
        if policy_content_idx == -1:
            errors.append("[X] Could not find existing policy content in Company Handbook")
        else:
            checks_passed.append("[C] Could find existing policy content in Company Handbook")
    
        if remote_work_heading_idx <= policy_content_idx:
            errors.append(f"[X] Remote Work Policy heading should be after existing policy content (policy content at idx {policy_content_idx}, heading at idx {remote_work_heading_idx})")
        else:
            checks_passed.append(f"[C] Remote Work Policy heading should be after existing policy content (policy content at idx {policy_content_idx}, heading at idx {remote_work_heading_idx})")
    
        # 6. Validate Remote Work Policy is before next major heading (if exists)
        if next_major_heading_idx != -1:
            if remote_work_heading_idx >= next_major_heading_idx:
                errors.append(f"[X] Remote Work Policy heading should be before next major section (heading at idx {remote_work_heading_idx}, next major at idx {next_major_heading_idx})")
            else:
                checks_passed.append(f"[C] Remote Work Policy heading should be before next major section (heading at idx {remote_work_heading_idx}, next major at idx {next_major_heading_idx})")
    
        # 7. Validate quote block exists and is positioned correctly
        if quote_block_idx == -1:
            errors.append("[X] Quote block with philosophical statement about flexibility and trust not found")
        else:
            checks_passed.append("[C] Quote block with philosophical statement about flexibility and trust found")
    
        if quote_block_idx <= remote_work_heading_idx:
            errors.append(f"[X] Quote block should be after Remote Work Policy heading (heading at idx {remote_work_heading_idx}, quote at idx {quote_block_idx})")
        else:
            checks_passed.append(f"[C] Quote block should be after Remote Work Policy heading (heading at idx {remote_work_heading_idx}, quote at idx {quote_block_idx})")
    
        # 8. Validate Eligibility and Guidelines heading exists
        if eligibility_heading_idx == -1:
            errors.append("[X] heading_3 '🏠 Eligibility and Guidelines' not found")
        else:
            checks_passed.append("[C] heading_3 '🏠 Eligibility and Guidelines' found")
    
        if eligibility_heading_idx <= quote_block_idx:
            errors.append(f"[X] Eligibility heading should be after quote block (quote at idx {quote_block_idx}, heading at idx {eligibility_heading_idx})")
        else:
            checks_passed.append(f"[C] Eligibility heading should be after quote block (quote at idx {quote_block_idx}, heading at idx {eligibility_heading_idx})")
    
        # 9. Validate Equipment and Setup heading exists
        if equipment_heading_idx == -1:
            errors.append("[X] heading_3 '💼 Equipment and Setup' not found")
        else:
            checks_passed.append("[C] heading_3 '💼 Equipment and Setup' found")
    
        if equipment_heading_idx <= eligibility_heading_idx:
            errors.append(f"[X] Equipment heading should be after Eligibility heading (eligibility at idx {eligibility_heading_idx}, equipment at idx {equipment_heading_idx})")
        else:
            checks_passed.append(f"[C] Equipment heading should be after Eligibility heading (eligibility at idx {eligibility_heading_idx}, equipment at idx {equipment_heading_idx})")
    
        # 10. Validate exactly 4 numbered list items in eligibility section
        if len(eligibility_numbered_items) != 4:
            errors.append(f"[X] Eligibility section should have exactly 4 numbered list items, found {len(eligibility_numbered_items)}")
        else:
            checks_passed.append(f"[C] Eligibility section should have exactly 4 numbered list items, found {len(eligibility_numbered_items)}")
    
        # Verify content of numbered items
        eligibility_items_content = []
        for item_idx in eligibility_numbered_items:
            item_content = handbook_blocks[item_idx].get("content", "")
            eligibility_items_content.append(item_content.lower())
    
        required_eligibility_terms = [
            ["employees", "eligible", "90", "probation"],
            ["core hours", "10", "3", "timezone"],
            ["internet", "25 mbps"],
            ["meetings", "video"]
        ]
    
        for terms_group in required_eligibility_terms:
            found = False
            for item_content in eligibility_items_content:
                if all(term in item_content for term in terms_group):
                    found = True
                    break
            if not found:
                errors.append(f"[X] Missing required eligibility item with terms: {terms_group}")
            else:
                checks_passed.append(f"[C] has required eligibility item with terms: {terms_group}")
    
        # 11. Validate exactly 3 bulleted list items in equipment section
        if len(equipment_bulleted_items) != 3:
            errors.append(f"[X] Equipment section should have exactly 3 bulleted list items, found {len(equipment_bulleted_items)}")
        else:
            checks_passed.append(f"[C] Equipment section should have exactly 3 bulleted list items, found {len(equipment_bulleted_items)}")
    
        # Verify content of bulleted items
        equipment_items_content = []
        for item_idx in equipment_bulleted_items:
            item_content = handbook_blocks[item_idx].get("content", "")
            equipment_items_content.append(item_content.lower())
    
        required_equipment_terms = [
            ["laptop", "software"],
            ["500", "stipend", "office"],
            ["internet", "reimbursement", "75"]
        ]
    
        for terms_group in required_equipment_terms:
            found = False
            for item_content in equipment_items_content:
                if all(term in item_content for term in terms_group):
                    found = True
                    break
            if not found:
                errors.append(f"[X] Missing required equipment item with terms: {terms_group}")
            else:
                checks_passed.append(f"[C] has required equipment item with terms: {terms_group}")
    
        # 12. Validate divider exists at the end
        if divider_idx == -1:
            errors.append("[X] Divider block not found at end of Remote Work Policy section")
        else:
            checks_passed.append("[C] Divider block found at end of Remote Work Policy section")
    
        if divider_idx <= equipment_heading_idx:
            errors.append(f"[X] Divider should be after Equipment section (equipment at idx {equipment_heading_idx}, divider at idx {divider_idx})")
        else:
            checks_passed.append(f"[C] Divider should be after Equipment section (equipment at idx {equipment_heading_idx}, divider at idx {divider_idx})")
    
        # 13. Validate section order and positioning
        if next_major_heading_idx != -1:
            if divider_idx >= next_major_heading_idx:
                errors.append(f"[X] Remote Work Policy section should end before next major section (divider at idx {divider_idx}, next major at idx {next_major_heading_idx})")
            else:
                checks_passed.append(f"[C] Remote Work Policy section should end before next major section (divider at idx {divider_idx}, next major at idx {next_major_heading_idx})")
    
        # ALL requirements met!
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: create-architecture-documentation-hub-v2
# Description: Create a comprehensive Architecture Documentation Hub page that
# aggregates all architecture pages with their icons and creates bookmark links
# =============================================================================
def _validate_agent_create_architecture_documentation_hub_2(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate Architecture Documentation Hub creation with:
    - New page created as child of 'Engineering Wiki'
    - heading_1 '🏗️ Architecture Documentation Hub'
    - Intro paragraph about system architecture
    - Gray callout with 📚 icon showing correct counts
    - heading_2 for each architecture page with pattern '[icon] [title] Documentation'
    - Bookmark blocks linking to architecture pages
    - Accurate counts: X total pages, Y main categories
    
    Returns 1.0 only if ALL requirements are met, otherwise 0.0
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Find the 'Architecture Documentation Hub' page
    try:
        hub_pages = _get_pages_by_filter(backend, {"title": "Architecture Documentation Hub"})
        if not hub_pages:
            errors.append("[X] Architecture Documentation Hub page not found")
        else:
            checks_passed.append("[C] Architecture Documentation Hub page found")
    
        hub_page = hub_pages[0]
        hub_id = hub_page.get("_id")
    
        # 2. Verify it's a child of 'Engineering Wiki'
        engineering_wiki_pages = _get_pages_by_filter(backend, {"title": "Engineering Wiki"})
        if not engineering_wiki_pages:
            errors.append("[X] Engineering Wiki page not found")
        else:
            checks_passed.append("[C] Engineering Wiki page found")
    
        engineering_wiki = engineering_wiki_pages[0]
        if hub_page.get("parentId") != engineering_wiki.get("_id"):
            errors.append("[X] Architecture Documentation Hub is not a child of 'Engineering Wiki'")
        else:
            checks_passed.append("[C] Architecture Documentation Hub is a child of 'Engineering Wiki'")
    
        # 3. Find the 'Architecture' page and all its descendants
        architecture_pages = _get_pages_by_filter(backend, {"title": "Architecture"})
        if not architecture_pages:
            errors.append("[X] Architecture page not found")
        else:
            checks_passed.append("[C] Architecture page found")
    
        architecture_page = architecture_pages[0]
        architecture_id = architecture_page.get("_id")
    
        # Get direct children of Architecture page
        direct_children = _get_pages_by_filter(backend, {"parentId": architecture_id})
        num_main_categories = len(direct_children)
    
        # Get all descendants (including nested sub-pages)
        def get_all_descendants(page_id):
            """Recursively get all descendant pages"""
            descendants = []
            children = _get_pages_by_filter(backend, {"parentId": page_id})
            for child in children:
                descendants.append(child)
                # Recursively get children of this child
                descendants.extend(get_all_descendants(child.get("_id")))
            return descendants
    
        all_architecture_descendants = get_all_descendants(architecture_id)
        total_architecture_pages = len(all_architecture_descendants)
    
        # 4. Get all blocks for the hub page
        hub_blocks = _get_blocks_by_filter(backend, {"pageId": hub_id})
    
        if len(hub_blocks) < 5:
            errors.append(f"[X] Architecture Documentation Hub needs at least 5 blocks, found {len(hub_blocks)}")
        else:
            checks_passed.append(f"[C] Architecture Documentation Hub needs at least 5 blocks, found {len(hub_blocks)}")
    
        # 5. Find key elements
        main_heading_idx = -1
        intro_paragraph_idx = -1
        gray_callout_idx = -1
    
        architecture_page_headings = []  # List of (idx, page_title, icon)
        bookmark_blocks = []  # List of (idx, url)
    
        for idx, block in enumerate(hub_blocks):
            block_type = block.get("type", "")
            block_content = block.get("content", "")
            block_properties = block.get("properties", {})
        
            # Find main heading
            if block_type == "heading1" and "🏗️" in block_content and "architecture documentation hub" in block_content.lower():
                main_heading_idx = idx
        
            # Find intro paragraph
            if block_type == "paragraph" and "comprehensive overview" in block_content.lower() and "system architecture" in block_content.lower():
                intro_paragraph_idx = idx
        
            # Find gray callout with counts
            if block_type == "callout":
                bg_color = block_properties.get("backgroundColor", "") if isinstance(block_properties, dict) else ""
                icon = block_properties.get("icon", "") if isinstance(block_properties, dict) else ""
                if "gray" in bg_color.lower():
                    if "📚" in icon and "references" in block_content.lower() and "documents" in block_content.lower():
                        gray_callout_idx = idx
        
            # Find heading_2 blocks for architecture pages
            if block_type == "heading2" and "documentation" in block_content.lower():
                # Extract icon and title
                architecture_page_headings.append((idx, block_content))
        
            # Find bookmark blocks
            if block_type == "bookmark":
                url = block_properties.get("url", "") if isinstance(block_properties, dict) else ""
                bookmark_blocks.append((idx, url))
    
        # 6. Validate main heading exists
        if main_heading_idx == -1:
            errors.append("[X] heading_1 '🏗️ Architecture Documentation Hub' not found")
        else:
            checks_passed.append("[C] heading_1 '🏗️ Architecture Documentation Hub' found")
    
        # 7. Validate intro paragraph exists and is after main heading
        if intro_paragraph_idx == -1:
            errors.append("[X] Intro paragraph about system architecture not found")
        else:
            checks_passed.append("[C] Intro paragraph about system architecture found")
    
        if intro_paragraph_idx <= main_heading_idx:
            errors.append(f"[X] Intro paragraph should be after main heading (heading at idx {main_heading_idx}, paragraph at idx {intro_paragraph_idx})")
        else:
            checks_passed.append(f"[C] Intro paragraph should be after main heading (heading at idx {main_heading_idx}, paragraph at idx {intro_paragraph_idx})")
    
        # 8. Validate gray callout exists
        if gray_callout_idx == -1:
            errors.append("[X] Gray callout with 📚 icon and document counts not found")
        else:
            checks_passed.append("[C] Gray callout with 📚 icon and document counts found")
    
        # Callout should be after intro paragraph
        if gray_callout_idx <= intro_paragraph_idx:
            errors.append(f"[X] Gray callout should be after intro paragraph (paragraph at idx {intro_paragraph_idx}, callout at idx {gray_callout_idx})")
        else:
            checks_passed.append(f"[C] Gray callout should be after intro paragraph (paragraph at idx {intro_paragraph_idx}, callout at idx {gray_callout_idx})")
    
        # 9. Validate callout contains correct counts
        callout_block = hub_blocks[gray_callout_idx]
        callout_content = callout_block.get("content", "")
    
        # Check for total pages count (including Architecture page itself + all descendants)
        expected_total = total_architecture_pages + 1  # +1 for Architecture page itself
    
        # The callout should reference the architecture hierarchy
        if str(total_architecture_pages) not in callout_content and str(expected_total) not in callout_content:
            errors.append(f"[X] Gray callout should mention architecture document count (expected {total_architecture_pages} or {expected_total}), callout: '{callout_content}'")
        else:
            checks_passed.append(f"[C] Gray callout should mention architecture document count (expected {total_architecture_pages} or {expected_total}), callout: '{callout_content}'")
    
        if str(num_main_categories) not in callout_content:
            errors.append(f"[X] Gray callout should mention {num_main_categories} main categories, callout: '{callout_content}'")
        else:
            checks_passed.append(f"[C] Gray callout should mention {num_main_categories} main categories, callout: '{callout_content}'")
    
        # 10. Validate each architecture page has a heading_2 with icon pattern
        if len(architecture_page_headings) < total_architecture_pages:
            errors.append(f"[X] Expected at least {total_architecture_pages} heading_2 blocks for architecture pages, found {len(architecture_page_headings)}")
        else:
            checks_passed.append(f"[C] Expected at least {total_architecture_pages} heading_2 blocks for architecture pages, found {len(architecture_page_headings)}")
    
        # Check heading pattern: should contain 'Documentation'
        for idx, heading_content in architecture_page_headings:
            if "documentation" not in heading_content.lower():
                errors.append(f"[X] Heading at idx {idx} should follow pattern '[icon] [title] Documentation', found: '{heading_content}'")
            else:
                checks_passed.append(f"[C] Heading at idx {idx} should follow pattern '[icon] [title] Documentation', found: '{heading_content}'")
    
        # 11. Validate bookmark blocks exist
        if len(bookmark_blocks) < total_architecture_pages:
            errors.append(f"[X] Expected at least {total_architecture_pages} bookmark blocks for architecture pages, found {len(bookmark_blocks)}")
        else:
            checks_passed.append(f"[C] Expected at least {total_architecture_pages} bookmark blocks for architecture pages, found {len(bookmark_blocks)}")
    
        # 12. Validate each heading_2 has a corresponding bookmark block after it
        for heading_idx, heading_content in architecture_page_headings:
            # Find the next bookmark after this heading
            found_bookmark = False
            for bookmark_idx, bookmark_url in bookmark_blocks:
                if bookmark_idx > heading_idx:
                    # Check if this bookmark is before the next heading
                    next_heading_idx = None
                    for next_h_idx, _ in architecture_page_headings:
                        if next_h_idx > heading_idx:
                            next_heading_idx = next_h_idx
                            break
                
                    if next_heading_idx is None or bookmark_idx < next_heading_idx:
                        found_bookmark = True
                        break
        
            if not found_bookmark:
                errors.append(f"[X] No bookmark block found after heading_2 at idx {heading_idx}: '{heading_content}'")
            else:
                checks_passed.append(f"[C] bookmark block found after heading_2 at idx {heading_idx}: '{heading_content}'")
    
        # ALL requirements met!
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: create-engineering-wiki-index-v2
# Description: Create an Engineering Wiki Index page that aggregates documentation,
# cross-references, contributors, and statistics
# =============================================================================
def _validate_agent_create_engineering_wiki_index(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate Engineering Wiki Index creation with:
    - New page created as child of 'Engineering Wiki'
    - heading_1 '🔍 Engineering Wiki Index'
    - Yellow callout with 📚 icon
    - heading_2 '📖 Documentation Structure' with hierarchical bulleted list
    - heading_2 '🔗 Cross-References' with bookmark blocks for relevant pages
    - heading_2 '👥 Contributors' with numbered list of collaborators
    - heading_2 '📊 Wiki Statistics' with accurate counts
    
    Returns 1.0 only if ALL requirements are met, otherwise 0.0
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Find the 'Engineering Wiki Index' page
    try:
        index_pages = _get_pages_by_filter(backend, {"title": "Engineering Wiki Index"})
        if not index_pages:
            errors.append("[X] Engineering Wiki Index page not found")
        else:
            checks_passed.append("[C] Engineering Wiki Index page found")
    
        index_page = index_pages[0]
        index_id = index_page.get("_id")
    
        # 2. Verify it's a child of 'Engineering Wiki'
        engineering_wiki_pages = _get_pages_by_filter(backend, {"title": "Engineering Wiki"})
        if not engineering_wiki_pages:
            errors.append("[X] Engineering Wiki page not found")
        else:
            checks_passed.append("[C] Engineering Wiki page found")
    
        engineering_wiki = engineering_wiki_pages[0]
        if index_page.get("parentId") != engineering_wiki.get("_id"):
            errors.append("[X] Engineering Wiki Index is not a child of 'Engineering Wiki'")
        else:
            checks_passed.append("[C] Engineering Wiki Index is a child of 'Engineering Wiki'")
    
        engineering_wiki_id = engineering_wiki.get("_id")
    
        # 3. Get Engineering Wiki sub-pages
        wiki_children = _get_pages_by_filter(backend, {"parentId": engineering_wiki_id})
    
        # 4. Find pages with relevant titles for cross-references
        all_pages = _get_pages_by_filter(backend, {})
        cross_ref_keywords = ["api", "documentation", "architecture", "engineering"]
        cross_ref_pages = []
        for page in all_pages:
            title = page.get("title", "").lower()
            if any(keyword in title for keyword in cross_ref_keywords):
                cross_ref_pages.append(page)
    
        # 5. Get contributors from Engineering Wiki sharing metadata
        wiki_collaborators = engineering_wiki.get("collaborators", [])
        if not isinstance(wiki_collaborators, list):
            wiki_collaborators = []
    
        # Count unique contributors
        unique_contributors = set()
        for collab in wiki_collaborators:
            if isinstance(collab, dict):
                email = collab.get("email", "")
                if email:
                    unique_contributors.add(email)
    
        num_contributors = len(unique_contributors)
    
        # 6. Count total documentation pages (Engineering Wiki + its descendants)
        def count_all_descendants(page_id):
            """Recursively count all descendant pages"""
            children = _get_pages_by_filter(backend, {"parentId": page_id})
            count = len(children)
            for child in children:
                count += count_all_descendants(child.get("_id"))
            return count
    
        total_doc_pages = count_all_descendants(engineering_wiki_id) + 1  # +1 for wiki itself
    
        # 7. Get all blocks for the index page
        index_blocks = _get_blocks_by_filter(backend, {"pageId": index_id})
    
        if len(index_blocks) < 8:
            errors.append(f"[X] Engineering Wiki Index needs at least 8 blocks, found {len(index_blocks)}")
        else:
            checks_passed.append(f"[C] Engineering Wiki Index needs at least 8 blocks, found {len(index_blocks)}")
    
        # 8. Find key elements
        main_heading_idx = -1
        yellow_callout_idx = -1
        doc_structure_heading_idx = -1
        cross_ref_heading_idx = -1
        contributors_heading_idx = -1
        statistics_heading_idx = -1
    
        bulleted_list_items = []
        bookmark_blocks = []
        numbered_list_items = []
        statistics_paragraphs = []
    
        for idx, block in enumerate(index_blocks):
            block_type = block.get("type", "")
            block_content = block.get("content", "")
            block_properties = block.get("properties", {})
        
            # Find main heading
            if block_type == "heading1" and "🔍" in block_content and "engineering wiki index" in block_content.lower():
                main_heading_idx = idx
        
            # Find yellow callout
            if block_type == "callout":
                bg_color = block_properties.get("backgroundColor", "") if isinstance(block_properties, dict) else ""
                if "yellow" in bg_color.lower():
                    if "📚" in block_content and "comprehensive" in block_content.lower():
                        yellow_callout_idx = idx
        
            # Find section headings
            if block_type == "heading2":
                if "📖" in block_content and "documentation structure" in block_content.lower():
                    doc_structure_heading_idx = idx
                elif "🔗" in block_content and "cross-references" in block_content.lower():
                    cross_ref_heading_idx = idx
                elif "👥" in block_content and "contributors" in block_content.lower():
                    contributors_heading_idx = idx
                elif "📊" in block_content and "wiki statistics" in block_content.lower():
                    statistics_heading_idx = idx
        
            # Collect bulleted list items for documentation structure
            if block_type == "bulletedList":
                if doc_structure_heading_idx != -1 and idx > doc_structure_heading_idx:
                    if cross_ref_heading_idx == -1 or idx < cross_ref_heading_idx:
                        bulleted_list_items.append((idx, block_content))
        
            # Collect bookmark blocks for cross-references
            if block_type == "bookmark":
                if cross_ref_heading_idx != -1 and idx > cross_ref_heading_idx:
                    if contributors_heading_idx == -1 or idx < contributors_heading_idx:
                        url = block_properties.get("url", "") if isinstance(block_properties, dict) else ""
                        bookmark_blocks.append((idx, url))
        
            # Collect numbered list items for contributors
            if block_type == "numberedList":
                if contributors_heading_idx != -1 and idx > contributors_heading_idx:
                    if statistics_heading_idx == -1 or idx < statistics_heading_idx:
                        numbered_list_items.append((idx, block_content))
        
            # Collect paragraphs for statistics
            if block_type == "paragraph":
                if statistics_heading_idx != -1 and idx > statistics_heading_idx:
                    statistics_paragraphs.append((idx, block_content))
    
        # 9. Validate main heading exists
        if main_heading_idx == -1:
            errors.append("[X] heading_1 '🔍 Engineering Wiki Index' not found")
        else:
            checks_passed.append("[C] heading_1 '🔍 Engineering Wiki Index' found")
    
        # 10. Validate yellow callout exists
        if yellow_callout_idx == -1:
            errors.append("[X] Yellow callout with '📚' icon not found")
        else:
            checks_passed.append("[C] Yellow callout with '📚' icon found")
    
        if yellow_callout_idx <= main_heading_idx:
            errors.append(f"[X] Yellow callout should be after main heading (heading at idx {main_heading_idx}, callout at idx {yellow_callout_idx})")
        else:
            checks_passed.append(f"[C] Yellow callout should be after main heading (heading at idx {main_heading_idx}, callout at idx {yellow_callout_idx})")
    
        # 11. Validate Documentation Structure section exists
        if doc_structure_heading_idx == -1:
            errors.append("[X] heading_2 '📖 Documentation Structure' not found")
        else:
            checks_passed.append("[C] heading_2 '📖 Documentation Structure' found")
    
        if doc_structure_heading_idx <= yellow_callout_idx:
            errors.append(f"[X] Documentation Structure heading should be after callout (callout at idx {yellow_callout_idx}, heading at idx {doc_structure_heading_idx})")
        else:
            checks_passed.append(f"[C] Documentation Structure heading should be after callout (callout at idx {yellow_callout_idx}, heading at idx {doc_structure_heading_idx})")
    
        # 12. Validate bulleted list exists in Documentation Structure
        if len(bulleted_list_items) == 0:
            errors.append("[X] Documentation Structure section should have bulleted list items showing wiki sub-pages")
        else:
            checks_passed.append("[C] Documentation Structure section should have bulleted list items showing wiki sub-pages")
    
        # 13. Validate Cross-References section exists
        if cross_ref_heading_idx == -1:
            errors.append("[X] heading_2 '🔗 Cross-References' not found")
        else:
            checks_passed.append("[C] heading_2 '🔗 Cross-References' found")
    
        if cross_ref_heading_idx <= doc_structure_heading_idx:
            errors.append(f"[X] Cross-References heading should be after Documentation Structure (doc structure at idx {doc_structure_heading_idx}, cross-ref at idx {cross_ref_heading_idx})")
        else:
            checks_passed.append(f"[C] Cross-References heading should be after Documentation Structure (doc structure at idx {doc_structure_heading_idx}, cross-ref at idx {cross_ref_heading_idx})")
    
        # 14. Validate bookmark blocks exist in Cross-References
        if len(bookmark_blocks) < 2:
            errors.append(f"[X] Cross-References section should have at least 2 bookmark blocks (API Documentation, Engineering Wiki, etc.), found {len(bookmark_blocks)}")
        else:
            checks_passed.append(f"[C] Cross-References section should have at least 2 bookmark blocks (API Documentation, Engineering Wiki, etc.), found {len(bookmark_blocks)}")
    
        # Check for specific pages in bookmarks
        required_pages = ["api documentation", "engineering wiki"]
        found_pages = []
        for page in all_pages:
            title = page.get("title", "").lower()
            if any(req in title for req in required_pages):
                found_pages.append(title)
    
        # 15. Validate Contributors section exists
        if contributors_heading_idx == -1:
            errors.append("[X] heading_2 '👥 Contributors' not found")
        else:
            checks_passed.append("[C] heading_2 '👥 Contributors' found")
    
        if contributors_heading_idx <= cross_ref_heading_idx:
            errors.append(f"[X] Contributors heading should be after Cross-References (cross-ref at idx {cross_ref_heading_idx}, contributors at idx {contributors_heading_idx})")
        else:
            checks_passed.append(f"[C] Contributors heading should be after Cross-References (cross-ref at idx {cross_ref_heading_idx}, contributors at idx {contributors_heading_idx})")
    
        # 16. Validate numbered list exists in Contributors section
        if len(numbered_list_items) < 3:
            errors.append(f"[X] Contributors section should have at least 3 numbered list items, found {len(numbered_list_items)}")
        else:
            checks_passed.append(f"[C] Contributors section should have at least 3 numbered list items, found {len(numbered_list_items)}")
    
        # Check for required contributors (Alice, Bob, Carol, David)
        required_contributors = ["alice", "bob", "carol", "david"]
        found_contributors = []
        for idx, item_content in numbered_list_items:
            content_lower = item_content.lower()
            for contrib in required_contributors:
                if contrib in content_lower:
                    found_contributors.append(contrib)
    
        if len(found_contributors) < 3:
            errors.append(f"[X] Contributors section should include Alice, Bob, Carol, David - found {found_contributors}")
        else:
            checks_passed.append(f"[C] Contributors section should include Alice, Bob, Carol, David - found {found_contributors}")
    
        # 17. Validate Wiki Statistics section exists
        if statistics_heading_idx == -1:
            errors.append("[X] heading_2 '📊 Wiki Statistics' not found")
        else:
            checks_passed.append("[C] heading_2 '📊 Wiki Statistics' found")
    
        if statistics_heading_idx <= contributors_heading_idx:
            errors.append(f"[X] Wiki Statistics heading should be after Contributors (contributors at idx {contributors_heading_idx}, statistics at idx {statistics_heading_idx})")
        else:
            checks_passed.append(f"[C] Wiki Statistics heading should be after Contributors (contributors at idx {contributors_heading_idx}, statistics at idx {statistics_heading_idx})")
    
        # 18. Validate statistics paragraphs with counts
        if len(statistics_paragraphs) < 2:
            errors.append(f"[X] Wiki Statistics section should have at least 2 paragraphs with counts, found {len(statistics_paragraphs)}")
        else:
            checks_passed.append(f"[C] Wiki Statistics section should have at least 2 paragraphs with counts, found {len(statistics_paragraphs)}")
    
        # Check for mention of documentation pages count
        found_pages_count = False
        found_contributors_count = False
    
        for idx, para_content in statistics_paragraphs:
            content_lower = para_content.lower()
            if "documentation" in content_lower or "pages" in content_lower:
                found_pages_count = True
            if "contributors" in content_lower:
                found_contributors_count = True
    
        if not found_pages_count:
            errors.append("[X] Wiki Statistics should mention total documentation pages count")
        else:
            checks_passed.append("[C] Wiki Statistics should mention total documentation pages count")
    
        if not found_contributors_count:
            errors.append("[X] Wiki Statistics should mention total contributors count")
        else:
            checks_passed.append("[C] Wiki Statistics should mention total contributors count")
    
        # ALL requirements met!
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: add-language-statistics-to-code-examples-v2
# Description: Insert a comprehensive Language Statistics section with analysis
# and DevOps examples into the Code Examples Repository page
# =============================================================================
def _validate_agent_add_language_statistics_to_code_examples(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate Language Statistics section insertion with:
    - Section positioned after 'Java Examples' section but before any images
    - heading_2 '📊 Language Statistics'
    - Yellow callout with heading_3 'Language Type Analysis' and bulleted list
    - Accurate counts: typed vs dynamic languages with percentages
    - Divider block
    - heading_3 '🏆 Most Common Languages' with sorted numbered list
    - heading_2 '🔧 DevOps Examples' with yaml code block
    - Description paragraph matching format
    
    Returns 1.0 only if ALL requirements are met, otherwise 0.0
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Find the 'Code Examples Repository' page
    try:
        repo_page = _find_page_by_title(final_state_backend, "Code Examples Repository")
        if not repo_page:
            errors.append("[X] Code Examples Repository page not found")
        else:
            checks_passed.append("[C] Code Examples Repository page found")
    
        repo_id = repo_page.get("_id")
    
        # 2. Get all blocks for the page
        page_blocks = _get_blocks_for_page(final_state_backend, repo_id)
    
        if len(page_blocks) < 10:
            errors.append(f"[X] Code Examples Repository needs more blocks, found {len(page_blocks)}")
        else:
            checks_passed.append(f"[C] Code Examples Repository needs more blocks, found {len(page_blocks)}")
    
        # 3. Count code blocks by language type
        typed_languages = ["typescript", "java", "rust", "go"]
        dynamic_languages = ["javascript", "python", "bash"]
    
        typed_count = 0
        dynamic_count = 0
        language_counts = {}
    
        # Languages to analyze (exclude yaml which is added as part of DevOps section)
        analyzed_languages = typed_languages + dynamic_languages + ["sql"]
    
        for block in page_blocks:
            if block.get("type") == "code":
                props = block.get("properties", {})
                if isinstance(props, dict):
                    lang = props.get("language", "").lower()
                    if lang:
                        # Count by type
                        if lang in typed_languages:
                            typed_count += 1
                        elif lang in dynamic_languages:
                            dynamic_count += 1
                        elif lang == "sql":
                            pass  # SQL is counted separately
                    
                        # Count individual languages (only analyzed languages, not yaml from DevOps section)
                        if lang in analyzed_languages:
                            language_counts[lang] = language_counts.get(lang, 0) + 1
    
        total_typed_dynamic = typed_count + dynamic_count
        typed_percentage = round((typed_count / total_typed_dynamic * 100) if total_typed_dynamic > 0 else 0)
        dynamic_percentage = round((dynamic_count / total_typed_dynamic * 100) if total_typed_dynamic > 0 else 0)
    
        # 4. Find key sections and elements
        java_section_end_idx = -1
        stats_heading_idx = -1
        yellow_callout_idx = -1
        type_analysis_h3_idx = -1
        divider_after_callout_idx = -1
        common_languages_h3_idx = -1
        devops_heading_idx = -1
        devops_code_idx = -1
        devops_description_idx = -1
        first_image_idx = -1
    
        type_analysis_bullets = []
        common_languages_numbered = []
    
        for idx, block in enumerate(page_blocks):
            block_type = block.get("type", "")
            block_content = block.get("content", "")
            block_properties = block.get("properties", {})
        
            # Find end of Java Examples section (the description paragraph)
            if block_type == "paragraph" and "common java pattern for production code" in block_content.lower():
                java_section_end_idx = idx
        
            # Find Language Statistics heading
            if block_type == "heading2" and "📊" in block_content and "language statistics" in block_content.lower():
                stats_heading_idx = idx
        
            # Find yellow callout
            if block_type == "callout":
                bg_color = block_properties.get("backgroundColor", "") if isinstance(block_properties, dict) else ""
                if "yellow" in bg_color.lower():
                    if stats_heading_idx != -1 and idx > stats_heading_idx:
                        if yellow_callout_idx == -1:
                            yellow_callout_idx = idx
        
            # Find Language Type Analysis heading_3 (inside callout)
            if block_type == "heading3" and "language type analysis" in block_content.lower():
                type_analysis_h3_idx = idx
        
            # Collect bulleted list items in the callout
            if block_type == "bulletedList":
                if yellow_callout_idx != -1 and idx > yellow_callout_idx:
                    content_lower = block_content.lower()
                    if any(term in content_lower for term in ["typed", "dynamic", "sql", "languages"]):
                        if divider_after_callout_idx == -1 or idx < divider_after_callout_idx:
                            type_analysis_bullets.append((idx, block_content))
        
            # Find divider after callout
            if block_type == "divider":
                if yellow_callout_idx != -1 and idx > yellow_callout_idx:
                    if divider_after_callout_idx == -1:
                        divider_after_callout_idx = idx
        
            # Find Most Common Languages heading_3
            if block_type == "heading3" and "🏆" in block_content and "most common languages" in block_content.lower():
                common_languages_h3_idx = idx
        
            # Collect numbered list items for common languages
            if block_type == "numberedList":
                if common_languages_h3_idx != -1 and idx > common_languages_h3_idx:
                    if devops_heading_idx == -1 or idx < devops_heading_idx:
                        common_languages_numbered.append((idx, block_content))
        
            # Find DevOps Examples heading
            if block_type == "heading2" and "🔧" in block_content and "devops examples" in block_content.lower():
                devops_heading_idx = idx
        
            # Find DevOps yaml code block
            if block_type == "code":
                if devops_heading_idx != -1 and idx > devops_heading_idx:
                    props = block.get("properties", {})
                    if isinstance(props, dict):
                        lang = props.get("language", "").lower()
                        if lang == "yaml":
                            if devops_code_idx == -1:
                                devops_code_idx = idx
        
            # Find DevOps description paragraph
            if block_type == "paragraph" and "common docker-compose pattern for production code" in block_content.lower():
                devops_description_idx = idx
        
            # Find first image block
            if block_type == "image":
                if first_image_idx == -1:
                    first_image_idx = idx
    
        # 5. Validate Java section end exists
        if java_section_end_idx == -1:
            errors.append("[X] Java Examples section end (description paragraph) not found")
        else:
            checks_passed.append("[C] Java Examples section end (description paragraph) found")
    
        # 6. Validate Language Statistics heading exists and is positioned correctly
        if stats_heading_idx == -1:
            errors.append("[X] heading_2 '📊 Language Statistics' not found")
        else:
            checks_passed.append("[C] heading_2 '📊 Language Statistics' found")
    
        # Must be after Java section
        if stats_heading_idx <= java_section_end_idx:
            errors.append(f"[X] Language Statistics heading must be after Java section end (Java end at idx {java_section_end_idx}, stats at idx {stats_heading_idx})")
        else:
            checks_passed.append(f"[C] Language Statistics heading must be after Java section end (Java end at idx {java_section_end_idx}, stats at idx {stats_heading_idx})")
    
        # Must be before first image (if exists)
        if first_image_idx != -1:
            if stats_heading_idx >= first_image_idx:
                errors.append(f"[X] Language Statistics heading must be before any images (stats at idx {stats_heading_idx}, first image at idx {first_image_idx})")
            else:
                checks_passed.append(f"[C] Language Statistics heading must be before any images (stats at idx {stats_heading_idx}, first image at idx {first_image_idx})")
    
        # 7. Validate yellow callout exists
        if yellow_callout_idx == -1:
            errors.append("[X] Yellow callout with Language Type Analysis not found")
        else:
            checks_passed.append("[C] Yellow callout with Language Type Analysis found")
    
        if yellow_callout_idx <= stats_heading_idx:
            errors.append(f"[X] Yellow callout should be after Language Statistics heading (heading at idx {stats_heading_idx}, callout at idx {yellow_callout_idx})")
        else:
            checks_passed.append(f"[C] Yellow callout should be after Language Statistics heading (heading at idx {stats_heading_idx}, callout at idx {yellow_callout_idx})")
    
        # 8. Validate Language Type Analysis heading_3 exists
        if type_analysis_h3_idx == -1:
            errors.append("[X] heading_3 'Language Type Analysis' not found in callout")
        else:
            checks_passed.append("[C] heading_3 'Language Type Analysis' found in callout")
    
        # 9. Validate bulleted list with type analysis (3 items: typed, dynamic, SQL)
        if len(type_analysis_bullets) != 3:
            errors.append(f"[X] Language Type Analysis should have exactly 3 bulleted list items (Typed, Dynamic, SQL), found {len(type_analysis_bullets)}")
        else:
            checks_passed.append(f"[C] Language Type Analysis should have exactly 3 bulleted list items (Typed, Dynamic, SQL), found {len(type_analysis_bullets)}")
    
        # Check for correct counts and percentages in bullets
        found_typed = False
        found_dynamic = False
        found_sql = False
    
        for idx, bullet_content in type_analysis_bullets:
            content_lower = bullet_content.lower()
            if "typed" in content_lower and str(typed_count) in bullet_content:
                found_typed = True
            if "dynamic" in content_lower and str(dynamic_count) in bullet_content:
                found_dynamic = True
            if "sql" in content_lower:
                found_sql = True
    
        if not found_typed:
            errors.append(f"[X] Typed Languages bullet should show count {typed_count}")
        else:
            checks_passed.append(f"[C] Typed Languages bullet should show count {typed_count}")
        if not found_dynamic:
            errors.append(f"[X] Dynamic Languages bullet should show count {dynamic_count}")
        else:
            checks_passed.append(f"[C] Dynamic Languages bullet should show count {dynamic_count}")
        if not found_sql:
            errors.append("[X] SQL (Query Language) bullet not found")
        else:
            checks_passed.append("[C] SQL (Query Language) bullet found")
    
        # 10. Validate divider exists after callout
        if divider_after_callout_idx == -1:
            errors.append("[X] Divider block not found after yellow callout")
        else:
            checks_passed.append("[C] Divider block found after yellow callout")
    
        if divider_after_callout_idx <= yellow_callout_idx:
            errors.append(f"[X] Divider should be after callout (callout at idx {yellow_callout_idx}, divider at idx {divider_after_callout_idx})")
        else:
            checks_passed.append(f"[C] Divider should be after callout (callout at idx {yellow_callout_idx}, divider at idx {divider_after_callout_idx})")
    
        # 11. Validate Most Common Languages heading_3 exists
        if common_languages_h3_idx == -1:
            errors.append("[X] heading_3 '🏆 Most Common Languages' not found")
        else:
            checks_passed.append("[C] heading_3 '🏆 Most Common Languages' found")
    
        if common_languages_h3_idx <= divider_after_callout_idx:
            errors.append(f"[X] Most Common Languages heading should be after divider (divider at idx {divider_after_callout_idx}, heading at idx {common_languages_h3_idx})")
        else:
            checks_passed.append(f"[C] Most Common Languages heading should be after divider (divider at idx {divider_after_callout_idx}, heading at idx {common_languages_h3_idx})")
    
        # 12. Validate numbered list for common languages
        if len(common_languages_numbered) < len(language_counts):
            errors.append(f"[X] Most Common Languages should have numbered list with all {len(language_counts)} languages, found {len(common_languages_numbered)}")
        else:
            checks_passed.append(f"[C] Most Common Languages should have numbered list with all {len(language_counts)} languages, found {len(common_languages_numbered)}")
    
        # 13. Validate DevOps Examples heading exists
        if devops_heading_idx == -1:
            errors.append("[X] heading_2 '🔧 DevOps Examples' not found")
        else:
            checks_passed.append("[C] heading_2 '🔧 DevOps Examples' found")
    
        if devops_heading_idx <= common_languages_h3_idx:
            errors.append(f"[X] DevOps Examples heading should be after Most Common Languages (common at idx {common_languages_h3_idx}, devops at idx {devops_heading_idx})")
        else:
            checks_passed.append(f"[C] DevOps Examples heading should be after Most Common Languages (common at idx {common_languages_h3_idx}, devops at idx {devops_heading_idx})")
    
        # DevOps section should be immediately after Language Statistics section
        # There shouldn't be other major sections in between
    
        # 14. Validate DevOps yaml code block exists
        if devops_code_idx == -1:
            errors.append("[X] DevOps yaml code block not found")
        else:
            checks_passed.append("[C] DevOps yaml code block found")
    
        if devops_code_idx <= devops_heading_idx:
            errors.append(f"[X] DevOps code block should be after DevOps heading (heading at idx {devops_heading_idx}, code at idx {devops_code_idx})")
        else:
            checks_passed.append(f"[C] DevOps code block should be after DevOps heading (heading at idx {devops_heading_idx}, code at idx {devops_code_idx})")
    
        # Check yaml code content
        devops_code_block = page_blocks[devops_code_idx]
        code_content = devops_code_block.get("content", "").lower()
        required_yaml_terms = ["version", "services", "app", "build", "ports", "8080", "environment", "node_env"]
    
        for term in required_yaml_terms:
            if term not in code_content:
                errors.append(f"[X] DevOps yaml code should contain '{term}'")
            else:
                checks_passed.append(f"[C] DevOps yaml code should contain '{term}'")
    
        # 15. Validate DevOps description paragraph exists
        if devops_description_idx == -1:
            errors.append("[X] DevOps description paragraph ('Common docker-compose pattern for production code.') not found")
        else:
            checks_passed.append("[C] DevOps description paragraph ('Common docker-compose pattern for production code.') found")
    
        if devops_description_idx <= devops_code_idx:
            errors.append(f"[X] DevOps description should be after code block (code at idx {devops_code_idx}, description at idx {devops_description_idx})")
        else:
            checks_passed.append(f"[C] DevOps description should be after code block (code at idx {devops_code_idx}, description at idx {devops_description_idx})")
    
        # ALL requirements met!
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: create-comprehensive-engineering-metrics-dashboard-v2
# Description: Create an Engineering Metrics Dashboard that analyzes code repository
# and bug tracking data with appropriate color-coded callout
# =============================================================================
def _validate_agent_create_comprehensive_engineering_metrics_dashboard(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate comprehensive Engineering Metrics Dashboard creation with:
    - New page created as child of 'Engineering Wiki'
    - heading1 '🎯 Engineering Metrics Dashboard'
    - heading2 '📊 Code Repository Analysis' with numbered list of metrics
    - Code language counts from 'Code Examples Repository'
    - heading2 '🐛 Bug Tracking Metrics' with bug statistics
    - Critical issues and overall resolution rates from 'Bug Tracker'
    - Color-coded callout (red/yellow/green) based on resolution rate threshold
    
    Returns 1.0 only if ALL requirements are met, otherwise 0.0
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Find the 'Engineering Metrics Dashboard' page
    try:
        dashboard_pages = _get_pages_by_filter(backend, {"title": "Engineering Metrics Dashboard"})
        if not dashboard_pages:
            errors.append("[X] Engineering Metrics Dashboard page not found")
        else:
            checks_passed.append("[C] Engineering Metrics Dashboard page found")
    
        dashboard_page = dashboard_pages[0]
        dashboard_id = dashboard_page.get("_id")
    
        # 2. Verify it's a child of 'Engineering Wiki'
        engineering_wiki_pages = _get_pages_by_filter(backend, {"title": "Engineering Wiki"})
        if not engineering_wiki_pages:
            errors.append("[X] Engineering Wiki page not found")
        else:
            checks_passed.append("[C] Engineering Wiki page found")
    
        engineering_wiki = engineering_wiki_pages[0]
        if dashboard_page.get("parentId") != engineering_wiki.get("_id"):
            errors.append("[X] Engineering Metrics Dashboard is not a child of 'Engineering Wiki'")
        else:
            checks_passed.append("[C] Engineering Metrics Dashboard is a child of 'Engineering Wiki'")
    
        # 3. Fetch Code Examples Repository and count code blocks
        repo_pages = _get_pages_by_filter(backend, {"title": "Code Examples Repository"})
        if not repo_pages:
            errors.append("[X] Code Examples Repository page not found")
        else:
            checks_passed.append("[C] Code Examples Repository page found")
    
        repo_page = repo_pages[0]
        repo_blocks = _get_blocks_by_filter(backend, {"pageId": repo_page.get("_id")})
    
        # Count code blocks by language
        language_counts = {}
        total_code_examples = 0
    
        for block in repo_blocks:
            if block.get("type") == "code":
                total_code_examples += 1
                props = block.get("properties", {})
                if isinstance(props, dict):
                    lang = props.get("language", "").lower()
                    if lang:
                        language_counts[lang] = language_counts.get(lang, 0) + 1
    
        # Find most used language
        most_used_lang = ""
        most_used_count = 0
        if language_counts:
            most_used_lang = max(language_counts, key=language_counts.get)
            most_used_count = language_counts[most_used_lang]
    
        # Count languages with 2+ examples
        languages_with_2_plus = [lang for lang, count in language_counts.items() if count >= 2]
    
        # 4. Fetch Bug Tracker and count bug statistics
        bug_tracker_pages = _get_pages_by_filter(backend, {"title": "Bug Tracker"})
        if not bug_tracker_pages:
            errors.append("[X] Bug Tracker page not found")
        else:
            checks_passed.append("[C] Bug Tracker page found")
    
        bug_tracker = bug_tracker_pages[0]
        bug_blocks = _get_blocks_by_filter(backend, {"pageId": bug_tracker.get("_id")})
    
        # Count critical issues
        critical_total = 0
        critical_resolved = 0
    
        # Count all bugs
        all_bugs_total = 0
        all_bugs_resolved = 0
    
        for block in bug_blocks:
            content = block.get("content", "").lower()
            block_type = block.get("type", "")
        
            # Look for todo blocks or list items mentioning bugs
            if block_type in ["todo", "bulletedList", "numberedList"]:
                # Check if it's a critical issue
                is_critical = "critical" in content or "high priority" in content or "urgent" in content
            
                # Check if resolved/completed
                is_resolved = False
                if block_type == "todo":
                    props = block.get("properties", {})
                    is_resolved = props.get("checked", False) if isinstance(props, dict) else False
                else:
                    # For list items, look for indicators of resolution
                    is_resolved = any(term in content for term in ["resolved", "fixed", "completed", "done", "closed"])
            
                if is_critical:
                    critical_total += 1
                    if is_resolved:
                        critical_resolved += 1
            
                # Count as a bug if it mentions bug/issue/defect
                if any(term in content for term in ["bug", "issue", "defect", "error", "problem"]):
                    all_bugs_total += 1
                    if is_resolved:
                        all_bugs_resolved += 1
    
        # Calculate resolution rates
        critical_resolution_rate = round((critical_resolved / critical_total * 100) if critical_total > 0 else 0)
        overall_resolution_rate = round((all_bugs_resolved / all_bugs_total * 100) if all_bugs_total > 0 else 0)
    
        # Determine callout color based on overall resolution rate
        if overall_resolution_rate < 70:
            expected_color = "red"
        elif overall_resolution_rate <= 85:
            expected_color = "yellow"
        else:
            expected_color = "green"
    
        # 5. Get all blocks for the dashboard page
        dashboard_blocks = _get_blocks_by_filter(backend, {"pageId": dashboard_id})
    
        if len(dashboard_blocks) < 6:
            errors.append(f"[X] Engineering Metrics Dashboard needs at least 6 blocks, found {len(dashboard_blocks)}")
        else:
            checks_passed.append(f"[C] Engineering Metrics Dashboard needs at least 6 blocks, found {len(dashboard_blocks)}")
    
        # 6. Find key elements
        main_heading_idx = -1
        code_analysis_heading_idx = -1
        bug_tracking_heading_idx = -1
        color_callout_idx = -1
        callout_color = ""
    
        code_metrics_list = []
        bug_metrics_paragraphs = []
    
        for idx, block in enumerate(dashboard_blocks):
            block_type = block.get("type", "")
            block_content = block.get("content", "")
            block_properties = block.get("properties", {})
        
            # Find main heading
            if block_type == "heading1" and "🎯" in block_content and "engineering metrics dashboard" in block_content.lower():
                main_heading_idx = idx
        
            # Find Code Repository Analysis heading
            if block_type == "heading2" and "📊" in block_content and "code repository analysis" in block_content.lower():
                code_analysis_heading_idx = idx
        
            # Find Bug Tracking Metrics heading
            if block_type == "heading2" and "🐛" in block_content and "bug tracking metrics" in block_content.lower():
                bug_tracking_heading_idx = idx
        
            # Collect numbered list items for code metrics
            if block_type == "numberedList":
                if code_analysis_heading_idx != -1 and idx > code_analysis_heading_idx:
                    if bug_tracking_heading_idx == -1 or idx < bug_tracking_heading_idx:
                        code_metrics_list.append((idx, block_content))
        
            # Collect paragraphs/text for bug metrics
            if block_type in ["paragraph", "bulletedList"]:
                if bug_tracking_heading_idx != -1 and idx > bug_tracking_heading_idx:
                    content_lower = block_content.lower()
                    if any(term in content_lower for term in ["critical", "resolution", "bugs", "issues"]):
                        bug_metrics_paragraphs.append((idx, block_content))
        
            # Find color-coded callout
            if block_type == "callout":
                bg_color = block_properties.get("backgroundColor", "") if isinstance(block_properties, dict) else ""
                if any(color in bg_color.lower() for color in ["red", "yellow", "green"]):
                    if bug_tracking_heading_idx != -1 and idx > bug_tracking_heading_idx:
                        if color_callout_idx == -1:
                            color_callout_idx = idx
                            callout_color = bg_color.lower()
    
        # 7. Validate main heading exists
        if main_heading_idx == -1:
            errors.append("[X] heading1 '🎯 Engineering Metrics Dashboard' not found")
        else:
            checks_passed.append("[C] heading1 '🎯 Engineering Metrics Dashboard' found")
    
        # 8. Validate Code Repository Analysis section exists
        if code_analysis_heading_idx == -1:
            errors.append("[X] heading2 '📊 Code Repository Analysis' not found")
        else:
            checks_passed.append("[C] heading2 '📊 Code Repository Analysis' found")
    
        if code_analysis_heading_idx <= main_heading_idx:
            errors.append(f"[X] Code Repository Analysis heading should be after main heading (main at idx {main_heading_idx}, code analysis at idx {code_analysis_heading_idx})")
        else:
            checks_passed.append(f"[C] Code Repository Analysis heading should be after main heading (main at idx {main_heading_idx}, code analysis at idx {code_analysis_heading_idx})")
    
        # 9. Validate numbered list with code metrics (3 items minimum)
        if len(code_metrics_list) < 3:
            errors.append(f"[X] Code Repository Analysis should have at least 3 numbered list items with metrics, found {len(code_metrics_list)}")
        else:
            checks_passed.append(f"[C] Code Repository Analysis should have at least 3 numbered list items with metrics, found {len(code_metrics_list)}")
    
        # Check for required metrics in the list
        found_total_examples = False
        found_most_used = False
        found_languages_2_plus = False
    
        for idx, item_content in code_metrics_list:
            content_lower = item_content.lower()
            if "total" in content_lower and "code" in content_lower and "examples" in content_lower:
                found_total_examples = True
            if "most used" in content_lower or "most common" in content_lower:
                found_most_used = True
            if "languages" in content_lower and ("2+" in item_content or "two" in content_lower):
                found_languages_2_plus = True
    
        if not found_total_examples:
            errors.append("[X] Code metrics should include 'Total code examples' count")
        else:
            checks_passed.append("[C] Code metrics should include 'Total code examples' count")
        if not found_most_used:
            errors.append("[X] Code metrics should include 'Most used language' information")
        else:
            checks_passed.append("[C] Code metrics should include 'Most used language' information")
        if not found_languages_2_plus:
            errors.append("[X] Code metrics should include 'Languages with 2+ examples' information")
        else:
            checks_passed.append("[C] Code metrics should include 'Languages with 2+ examples' information")
    
        # 10. Validate Bug Tracking Metrics section exists
        if bug_tracking_heading_idx == -1:
            errors.append("[X] heading2 '🐛 Bug Tracking Metrics' not found")
        else:
            checks_passed.append("[C] heading2 '🐛 Bug Tracking Metrics' found")
    
        if bug_tracking_heading_idx <= code_analysis_heading_idx:
            errors.append(f"[X] Bug Tracking Metrics heading should be after Code Repository Analysis (code at idx {code_analysis_heading_idx}, bug at idx {bug_tracking_heading_idx})")
        else:
            checks_passed.append(f"[C] Bug Tracking Metrics heading should be after Code Repository Analysis (code at idx {code_analysis_heading_idx}, bug at idx {bug_tracking_heading_idx})")
    
        # 11. Validate bug metrics paragraphs/text
        if len(bug_metrics_paragraphs) < 2:
            errors.append(f"[X] Bug Tracking Metrics should have at least 2 text elements with bug statistics, found {len(bug_metrics_paragraphs)}")
        else:
            checks_passed.append(f"[C] Bug Tracking Metrics should have at least 2 text elements with bug statistics, found {len(bug_metrics_paragraphs)}")
    
        # Check for critical issues and overall resolution rate mentions
        found_critical_metrics = False
        found_overall_rate = False
    
        for idx, para_content in bug_metrics_paragraphs:
            content_lower = para_content.lower()
            if "critical" in content_lower and ("resolved" in content_lower or "resolution" in content_lower):
                found_critical_metrics = True
            if ("overall" in content_lower or "total" in content_lower) and "resolution" in content_lower:
                found_overall_rate = True
    
        if not found_critical_metrics:
            errors.append("[X] Bug metrics should include critical issues resolved statistics")
        else:
            checks_passed.append("[C] Bug metrics should include critical issues resolved statistics")
        if not found_overall_rate:
            errors.append("[X] Bug metrics should include overall bug resolution rate")
        else:
            checks_passed.append("[C] Bug metrics should include overall bug resolution rate")
    
        # 12. Validate color-coded callout exists
        if color_callout_idx == -1:
            errors.append("[X] Color-coded callout (red/yellow/green) not found in Bug Tracking section")
        else:
            checks_passed.append("[C] Color-coded callout (red/yellow/green) found in Bug Tracking section")
    
        # 13. Validate callout color matches resolution rate threshold
        if expected_color not in callout_color:
            errors.append(f"[X] Callout color should be {expected_color} based on {overall_resolution_rate}% resolution rate, found: {callout_color}")
        else:
            checks_passed.append(f"[C] Callout color should be {expected_color} based on {overall_resolution_rate}% resolution rate, found: {callout_color}")
    
        # 14. Validate callout has appropriate message
        callout_block = dashboard_blocks[color_callout_idx]
        callout_content = callout_block.get("content", "").lower()
    
        # The message should be appropriate to the color/threshold
        if expected_color == "red" and not any(term in callout_content for term in ["attention", "warning", "concern", "improvement", "low"]):
            errors.append(f"[X] Red callout should have a warning/concern message (resolution rate: {overall_resolution_rate}%)")
        elif expected_color == "green" and not any(term in callout_content for term in ["excellent", "great", "good", "well", "high"]):
            errors.append(f"[X] Green callout should have a positive message (resolution rate: {overall_resolution_rate}%)")
        else:
            checks_passed.append(f"[C] Green callout should have a positive message (resolution rate: {overall_resolution_rate}%)")
    
        # ALL requirements met!
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: create-meeting-analytics-section-v2
# Description: On Meeting Notes main page, create comprehensive meeting analytics
# section that fetches child pages, counts blocks/todos/headings, calculates
# completion rates, and provides effectiveness score with recommendations
# =============================================================================
def _validate_agent_create_meeting_analytics_section(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate creation of meeting analytics section on Meeting Notes page with:
    - heading_2 '📊 Meeting Analytics' positioned after 'Meeting Types' section
    - For each child page (Sprint Planning, Team Retrospective):
      * Count total blocks, heading blocks, todo blocks
      * Calculate completion rate from checked/total todos
      * Create table-like structure with bulleted lists showing metrics
    - heading_3 '🎯 Meeting Effectiveness Score'
    - Green callout if avg completion rate >70% AND avg blocks >8, else yellow
    - Numbered list of data-driven recommendations
    
    Returns 1.0 only if ALL requirements are met, otherwise 0.0
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Find the 'Meeting Notes' page
    try:
        meeting_notes_pages = _get_pages_by_filter(backend, {"title": "Meeting Notes"})
        if not meeting_notes_pages:
            errors.append("[X] Meeting Notes page not found")
        else:
            checks_passed.append("[C] Meeting Notes page found")
    
        meeting_notes_page = meeting_notes_pages[0]
        meeting_notes_id = meeting_notes_page.get("_id")
    
        # 2. Get all blocks for Meeting Notes page
        meeting_notes_blocks = _get_blocks_by_filter(backend, {"pageId": meeting_notes_id})
    
        if len(meeting_notes_blocks) < 5:
            errors.append(f"[X] Meeting Notes needs sufficient blocks for analytics section, found {len(meeting_notes_blocks)}")
        else:
            checks_passed.append(f"[C] Meeting Notes needs sufficient blocks for analytics section, found {len(meeting_notes_blocks)}")
    
        # 3. Find 'Meeting Types' section and analytics section
        meeting_types_heading_idx = -1
        analytics_heading_idx = -1
        effectiveness_heading_idx = -1
        effectiveness_callout_idx = -1
        recommendations_list_start_idx = -1
    
        # Track meeting-specific sections
        sprint_planning_section_idx = -1
        team_retro_section_idx = -1
    
        sprint_planning_bullets = []
        team_retro_bullets = []
    
        recommendations_count = 0
    
        for idx, block in enumerate(meeting_notes_blocks):
            block_type = block.get("type", "")
            block_content = block.get("content", "")
            block_properties = block.get("properties", {})
        
            # Find Meeting Types heading
            if block_type in ["heading1", "heading2"] and "meeting types" in block_content.lower():
                meeting_types_heading_idx = idx
        
            # Find Meeting Analytics heading
            if block_type == "heading2" and "📊" in block_content and "meeting analytics" in block_content.lower():
                analytics_heading_idx = idx
        
            # Find Meeting Effectiveness Score heading
            if block_type == "heading3" and "🎯" in block_content and "meeting effectiveness score" in block_content.lower():
                effectiveness_heading_idx = idx
        
            # Find Sprint Planning section
            if "📅" in block_content and "sprint planning" in block_content.lower():
                sprint_planning_section_idx = idx
        
            # Find Team Retrospective section
            if "📅" in block_content and "team retrospective" in block_content.lower():
                team_retro_section_idx = idx
        
            # Collect bulleted list items for Sprint Planning section
            if block_type == "bulletedList" and sprint_planning_section_idx != -1:
                if team_retro_section_idx == -1 or idx < team_retro_section_idx:
                    if idx > sprint_planning_section_idx:
                        content_lower = block_content.lower()
                        if any(term in content_lower for term in ["total content blocks:", "action items:", "completion rate:"]):
                            sprint_planning_bullets.append({
                                "idx": idx,
                                "content": block_content
                            })
        
            # Collect bulleted list items for Team Retrospective section
            if block_type == "bulletedList" and team_retro_section_idx != -1:
                if idx > team_retro_section_idx:
                    # Make sure we're before the effectiveness heading
                    if effectiveness_heading_idx == -1 or idx < effectiveness_heading_idx:
                        content_lower = block_content.lower()
                        if any(term in content_lower for term in ["total content blocks:", "action items:", "completion rate:"]):
                            team_retro_bullets.append({
                                "idx": idx,
                                "content": block_content
                            })
        
            # Find effectiveness callout (green or yellow)
            if block_type == "callout" and effectiveness_heading_idx != -1 and idx > effectiveness_heading_idx:
                bg_color = block_properties.get("backgroundColor", "") if isinstance(block_properties, dict) else ""
                if "green" in bg_color.lower() or "yellow" in bg_color.lower():
                    content_lower = block_content.lower()
                    if "meeting" in content_lower and ("productive" in content_lower or "improving" in content_lower or "structure" in content_lower):
                        effectiveness_callout_idx = idx
        
            # Find numbered list items (recommendations)
            if block_type == "numberedList":
                if effectiveness_callout_idx != -1 and idx > effectiveness_callout_idx:
                    recommendations_count += 1
                    if recommendations_list_start_idx == -1:
                        recommendations_list_start_idx = idx
    
        # 4. Validate Meeting Types heading exists
        if meeting_types_heading_idx == -1:
            errors.append("[X] Meeting Types heading not found on Meeting Notes page")
        else:
            checks_passed.append("[C] Meeting Types heading found on Meeting Notes page")
    
        # 5. Validate Meeting Analytics heading exists
        if analytics_heading_idx == -1:
            errors.append("[X] heading_2 '📊 Meeting Analytics' not found")
        else:
            checks_passed.append("[C] heading_2 '📊 Meeting Analytics' found")
    
        # 6. Validate Analytics section is positioned after Meeting Types
        if analytics_heading_idx <= meeting_types_heading_idx:
            errors.append(f"[X] Meeting Analytics heading should be after Meeting Types heading (Meeting Types at idx {meeting_types_heading_idx}, Analytics at idx {analytics_heading_idx})")
        else:
            checks_passed.append(f"[C] Meeting Analytics heading should be after Meeting Types heading (Meeting Types at idx {meeting_types_heading_idx}, Analytics at idx {analytics_heading_idx})")
    
        # 7. Get child pages of Meeting Notes
        child_pages = _get_pages_by_filter(backend, {"parentId": meeting_notes_id})
    
        # Find Sprint Planning and Team Retrospective child pages
        sprint_planning_page = None
        team_retro_page = None
    
        for child in child_pages:
            title_lower = child.get("title", "").lower()
            if "sprint planning" in title_lower:
                sprint_planning_page = child
            elif "team retrospective" in title_lower or "retrospective" in title_lower:
                team_retro_page = child
    
        if not sprint_planning_page:
            errors.append("[X] Sprint Planning child page not found under Meeting Notes")
        else:
            checks_passed.append("[C] Sprint Planning child page found under Meeting Notes")
    
        if not team_retro_page:
            errors.append("[X] Team Retrospective child page not found under Meeting Notes")
        else:
            checks_passed.append("[C] Team Retrospective child page found under Meeting Notes")
    
        # 8. Analyze Sprint Planning page
        sprint_blocks = _get_blocks_by_filter(backend, {"pageId": sprint_planning_page.get("_id")})
        sprint_total_blocks = len(sprint_blocks)
        sprint_heading_blocks = sum(1 for b in sprint_blocks if b.get("type", "") in ["heading1", "heading2", "heading3"])
        sprint_todo_blocks = sum(1 for b in sprint_blocks if b.get("type", "") == "todo")
        sprint_checked_todos = sum(1 for b in sprint_blocks if b.get("type", "") == "todo" and b.get("properties", {}).get("checked", False))
        sprint_completion_rate = round((sprint_checked_todos / sprint_todo_blocks * 100), 1) if sprint_todo_blocks > 0 else 0
    
        # 9. Analyze Team Retrospective page
        retro_blocks = _get_blocks_by_filter(backend, {"pageId": team_retro_page.get("_id")})
        retro_total_blocks = len(retro_blocks)
        retro_heading_blocks = sum(1 for b in retro_blocks if b.get("type", "") in ["heading1", "heading2", "heading3"])
        retro_todo_blocks = sum(1 for b in retro_blocks if b.get("type", "") == "todo")
        retro_checked_todos = sum(1 for b in retro_blocks if b.get("type", "") == "todo" and b.get("properties", {}).get("checked", False))
        retro_completion_rate = round((retro_checked_todos / retro_todo_blocks * 100), 1) if retro_todo_blocks > 0 else 0
    
        # 10. Validate Sprint Planning section exists with metrics
        if sprint_planning_section_idx == -1:
            errors.append("[X] Sprint Planning section not found in Meeting Analytics (should have '📅 Sprint Planning - Jan 15:' or similar)")
        else:
            checks_passed.append("[C] Sprint Planning section found in Meeting Analytics (should have '📅 Sprint Planning - Jan 15:' or similar)")
    
        # 11. Validate Sprint Planning has 3 bulleted list items showing metrics
        if len(sprint_planning_bullets) < 3:
            errors.append(f"[X] Sprint Planning section should have at least 3 bulleted list items showing metrics (total blocks, action items, completion rate), found {len(sprint_planning_bullets)}")
        else:
            checks_passed.append(f"[C] Sprint Planning section should have at least 3 bulleted list items showing metrics (total blocks, action items, completion rate), found {len(sprint_planning_bullets)}")
    
        # Validate Sprint Planning metrics are present in bullet points
        sprint_bullets_text = " ".join([b["content"].lower() for b in sprint_planning_bullets])
    
        if "total content blocks:" not in sprint_bullets_text:
            errors.append("[X] Sprint Planning section missing 'Total content blocks: [X]' bullet point")
        else:
            checks_passed.append("[C] Sprint Planning section has 'Total content blocks: [X]' bullet point")
    
        if "action items:" not in sprint_bullets_text:
            errors.append("[X] Sprint Planning section missing 'Action items: [Y]' bullet point")
        else:
            checks_passed.append("[C] Sprint Planning section has 'Action items: [Y]' bullet point")
    
        if "completion rate:" not in sprint_bullets_text:
            errors.append("[X] Sprint Planning section missing 'Completion rate: [Z]%' bullet point")
        else:
            checks_passed.append("[C] Sprint Planning section has 'Completion rate: [Z]%' bullet point")
    
        # 12. Validate Team Retrospective section exists with metrics
        if team_retro_section_idx == -1:
            errors.append("[X] Team Retrospective section not found in Meeting Analytics")
        else:
            checks_passed.append("[C] Team Retrospective section found in Meeting Analytics")
    
        # 13. Validate Team Retrospective has 3 bulleted list items showing metrics
        if len(team_retro_bullets) < 3:
            errors.append(f"[X] Team Retrospective section should have at least 3 bulleted list items showing metrics, found {len(team_retro_bullets)}")
        else:
            checks_passed.append(f"[C] Team Retrospective section should have at least 3 bulleted list items showing metrics, found {len(team_retro_bullets)}")
    
        # Validate Team Retrospective metrics are present
        retro_bullets_text = " ".join([b["content"].lower() for b in team_retro_bullets])
    
        if "total content blocks:" not in retro_bullets_text:
            errors.append("[X] Team Retrospective section missing 'Total content blocks: [X]' bullet point")
        else:
            checks_passed.append("[C] Team Retrospective section has 'Total content blocks: [X]' bullet point")
    
        if "action items:" not in retro_bullets_text:
            errors.append("[X] Team Retrospective section missing 'Action items: [Y]' bullet point")
        else:
            checks_passed.append("[C] Team Retrospective section has 'Action items: [Y]' bullet point")
    
        if "completion rate:" not in retro_bullets_text:
            errors.append("[X] Team Retrospective section missing 'Completion rate: [Z]%' bullet point")
        else:
            checks_passed.append("[C] Team Retrospective section has 'Completion rate: [Z]%' bullet point")
    
        # 14. Validate Meeting Effectiveness Score heading exists
        if effectiveness_heading_idx == -1:
            errors.append("[X] heading_3 '🎯 Meeting Effectiveness Score' not found")
        else:
            checks_passed.append("[C] heading_3 '🎯 Meeting Effectiveness Score' found")
    
        # 15. Validate effectiveness heading is after both meeting sections
        if effectiveness_heading_idx <= sprint_planning_section_idx or effectiveness_heading_idx <= team_retro_section_idx:
            errors.append(f"[X] Effectiveness Score heading should be after both meeting sections (Sprint at {sprint_planning_section_idx}, Retro at {team_retro_section_idx}, Effectiveness at {effectiveness_heading_idx})")
        else:
            checks_passed.append(f"[C] Effectiveness Score heading should be after both meeting sections (Sprint at {sprint_planning_section_idx}, Retro at {team_retro_section_idx}, Effectiveness at {effectiveness_heading_idx})")
    
        # 16. Calculate expected effectiveness score
        avg_completion_rate = (sprint_completion_rate + retro_completion_rate) / 2
        avg_blocks = (sprint_total_blocks + retro_total_blocks) / 2
    
        is_productive = avg_completion_rate > 70 and avg_blocks > 8
        expected_color = "green" if is_productive else "yellow"
    
        # 17. Validate effectiveness callout exists
        if effectiveness_callout_idx == -1:
            errors.append(f"[X] Effectiveness callout not found (expected {expected_color} callout based on avg completion {avg_completion_rate:.1f}% and avg blocks {avg_blocks:.1f})")
        else:
            checks_passed.append(f"[C] Effectiveness callout found (expected {expected_color} callout based on avg completion {avg_completion_rate:.1f}% and avg blocks {avg_blocks:.1f})")
    
        # 18. Validate callout color matches calculation
        callout_block = meeting_notes_blocks[effectiveness_callout_idx]
        callout_bg = callout_block.get("properties", {}).get("backgroundColor", "") if isinstance(callout_block.get("properties"), dict) else ""
    
        if expected_color not in callout_bg.lower():
            errors.append(f"[X] Callout should be {expected_color} based on avg completion rate {avg_completion_rate:.1f}% and avg blocks {avg_blocks:.1f}, but found: {callout_bg}")
        else:
            checks_passed.append(f"[C] Callout should be {expected_color} based on avg completion rate {avg_completion_rate:.1f}% and avg blocks {avg_blocks:.1f}, but found: {callout_bg}")
    
        # 19. Validate recommendations numbered list exists
        if recommendations_list_start_idx == -1 or recommendations_count < 1:
            errors.append("[X] Numbered list of recommendations not found after effectiveness callout")
        else:
            checks_passed.append("[C] Numbered list of recommendations found after effectiveness callout")
    
        # 20. Validate recommendations are after effectiveness callout
        if recommendations_list_start_idx <= effectiveness_callout_idx:
            errors.append(f"[X] Recommendations numbered list should be after effectiveness callout (callout at {effectiveness_callout_idx}, recommendations at {recommendations_list_start_idx})")
        else:
            checks_passed.append(f"[C] Recommendations numbered list should be after effectiveness callout (callout at {effectiveness_callout_idx}, recommendations at {recommendations_list_start_idx})")
    
        # ALL requirements met!
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: reorganize-project-documentation-v2
# Description: Reorganize Comprehensive Product Requirements Document page with child pages index,
# alphabetically sorted sections with dividers, and reorganization metadata
# =============================================================================
def _validate_agent_reorganize_project_documentation_2(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate Comprehensive Product Requirements Document reorganization with:
    - If child pages exist: heading_2 '📚 Documentation Structure' at beginning with numbered list of children
    - All heading_2 sections reordered alphabetically (ignoring emojis)
    - Divider blocks between each reordered section
    - heading_2 '📅 Last Reorganized' at end
    - Blue callout with paragraph showing date and counts (TODO: should check for bold formatting in future)
    
    Returns 1.0 only if ALL requirements are met, otherwise 0.0
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Find the 'Comprehensive Product Requirements Document' page
    try:
        doc_pages = _get_pages_by_filter(backend, {"title": "Comprehensive Product Requirements Document"})
        if not doc_pages:
            errors.append("[X] Comprehensive Product Requirements Document page not found")
        else:
            checks_passed.append("[C] Comprehensive Product Requirements Document page found")
    
        doc_page = doc_pages[0]
        doc_id = doc_page.get("_id")
    
        # 2. Get all blocks for the page
        page_blocks = _get_blocks_by_filter(backend, {"pageId": doc_id})
    
        if len(page_blocks) < 5:
            errors.append(f"[X] Comprehensive Product Requirements Document needs sufficient blocks for reorganization, found {len(page_blocks)}")
        else:
            checks_passed.append(f"[C] Comprehensive Product Requirements Document needs sufficient blocks for reorganization, found {len(page_blocks)}")
    
        # 3. Get child pages
        child_pages = _get_pages_by_filter(backend, {"parentId": doc_id})
        has_children = len(child_pages) > 0
    
        # 4. Find key blocks
        doc_structure_heading_idx = -1
        doc_structure_numbered_items = []
        last_reorg_heading_idx = -1
        last_reorg_callout_idx = -1
    
        heading2_blocks = []  # To check alphabetical order
        divider_indices = []
    
        # Sort blocks by order
        blocks_by_order = sorted(
            [(block.get("order", 0), idx, block) for idx, block in enumerate(page_blocks)],
            key=lambda x: x[0]
        )
    
        for order, idx, block in blocks_by_order:
            block_type = block.get("type", "")
            block_content = block.get("content", "")
        
            # Find Documentation Structure heading
            if block_type == "heading2" and "📚" in block_content and "documentation structure" in block_content.lower():
                doc_structure_heading_idx = idx
        
            # Find Last Reorganized heading
            if block_type == "heading2" and "📅" in block_content and "last reorganized" in block_content.lower():
                last_reorg_heading_idx = idx
        
            # Find numbered list items after Documentation Structure
            if block_type == "numberedList":
                if doc_structure_heading_idx != -1 and idx > doc_structure_heading_idx:
                    # Check if this is before the next heading2 or within reasonable range
                    if last_reorg_heading_idx == -1 or idx < last_reorg_heading_idx:
                        # Check if content contains child page info (icon and title format)
                        if len(doc_structure_numbered_items) < len(child_pages):
                            doc_structure_numbered_items.append({
                                "idx": idx,
                                "content": block_content
                            })
        
            # Collect all heading2 blocks (excluding special ones)
            if block_type == "heading2":
                if "documentation structure" not in block_content.lower() and "last reorganized" not in block_content.lower():
                    # Remove emojis for sorting comparison
                    clean_content = "".join(char for char in block_content if not char.isascii() or char.isalnum() or char.isspace())
                    heading2_blocks.append({
                        "idx": idx,
                        "content": block_content,
                        "clean": clean_content.strip().lower()
                    })
        
            # Find dividers
            if block_type == "divider":
                divider_indices.append(idx)
        
            # Find callout after Last Reorganized heading
            if block_type == "callout":
                if last_reorg_heading_idx != -1 and idx > last_reorg_heading_idx:
                    if last_reorg_callout_idx == -1:  # Get the first one after heading
                        callout_props = block.get("properties", {})
                        bg_color = callout_props.get("backgroundColor", "") if isinstance(callout_props, dict) else ""
                        if "blue" in bg_color.lower():
                            last_reorg_callout_idx = idx
    
        # 5. If child pages exist, validate Documentation Structure section
        if has_children:
            if doc_structure_heading_idx == -1:
                errors.append(f"[X] Child pages exist ({len(child_pages)}), but '📚 Documentation Structure' heading_2 not found at beginning")
            else:
                checks_passed.append(f"[C] Child pages exist ({len(child_pages)}), but '📚 Documentation Structure' heading_2 found at beginning")
        
            # Should be early in the page
            if doc_structure_heading_idx > 3:
                errors.append(f"[X] Documentation Structure heading should be at the beginning, found at idx {doc_structure_heading_idx}")
            else:
                checks_passed.append(f"[C] Documentation Structure heading should be at the beginning, found at idx {doc_structure_heading_idx}")
        
            # Check numbered list has entries for each child page
            if len(doc_structure_numbered_items) < len(child_pages):
                errors.append(f"[X] Documentation Structure should have numbered list with {len(child_pages)} items (one per child page), found {len(doc_structure_numbered_items)}")
            else:
                checks_passed.append(f"[C] Documentation Structure should have numbered list with {len(child_pages)} items (one per child page), found {len(doc_structure_numbered_items)}")
    
        # 6. Validate heading2 sections are in alphabetical order
        if len(heading2_blocks) < 2:
            errors.append("[X] At least 2 heading_2 sections needed to verify alphabetical ordering")
        else:
            checks_passed.append("[C] At least 2 heading_2 sections needed to verify alphabetical ordering")
    
        # Check if sorted
        sorted_headings = sorted(heading2_blocks, key=lambda x: x["clean"])
        original_order = [h["clean"] for h in heading2_blocks]
        sorted_order = [h["clean"] for h in sorted_headings]
    
        if original_order != sorted_order:
            errors.append(f"[X] heading_2 sections not in alphabetical order. Found order: {[h['content'] for h in heading2_blocks]}, expected: {[h['content'] for h in sorted_headings]}")
        else:
            checks_passed.append(f"[C] heading_2 sections in alphabetical order. Found order: {[h['content'] for h in heading2_blocks]}, expected: {[h['content'] for h in sorted_headings]}")
    
        # 7. Validate dividers between sections
        # There should be dividers between the heading2 blocks
        expected_divider_count = len(heading2_blocks) - 1
        if len(divider_indices) < expected_divider_count:
            errors.append(f"[X] Expected at least {expected_divider_count} divider blocks between {len(heading2_blocks)} sections, found {len(divider_indices)}")
        else:
            checks_passed.append(f"[C] Expected at least {expected_divider_count} divider blocks between {len(heading2_blocks)} sections, found {len(divider_indices)}")
    
        # 8. Validate Last Reorganized section
        if last_reorg_heading_idx == -1:
            errors.append("[X] '📅 Last Reorganized' heading_2 not found at end")
        else:
            checks_passed.append("[C] '📅 Last Reorganized' heading_2 found at end")
    
        # Should be near the end
        if last_reorg_heading_idx < len(page_blocks) - 5:
            errors.append(f"[X] Last Reorganized heading should be near the end, found at idx {last_reorg_heading_idx} out of {len(page_blocks)}")
        else:
            checks_passed.append(f"[C] Last Reorganized heading should be near the end, found at idx {last_reorg_heading_idx} out of {len(page_blocks)}")
    
        # 9. Validate Blue callout with metadata
        if last_reorg_callout_idx == -1:
            errors.append("[X] Blue callout not found after Last Reorganized heading")
        else:
            checks_passed.append("[C] Blue callout found after Last Reorganized heading")
    
        if last_reorg_callout_idx <= last_reorg_heading_idx:
            errors.append(f"[X] Callout should be after Last Reorganized heading (heading at {last_reorg_heading_idx}, callout at {last_reorg_callout_idx})")
        else:
            checks_passed.append(f"[C] Callout should be after Last Reorganized heading (heading at {last_reorg_heading_idx}, callout at {last_reorg_callout_idx})")
    
        # 10. Validate callout content has required information
        callout_block = page_blocks[last_reorg_callout_idx]
        callout_content = callout_block.get("content", "").lower()
    
        if "date:" not in callout_content:
            errors.append("[X] Callout missing 'Date:' information")
        else:
            checks_passed.append("[C] Callout has 'Date:' information")
    
        if "total sections:" not in callout_content and "sections:" not in callout_content:
            errors.append("[X] Callout missing 'Total sections:' count")
        else:
            checks_passed.append("[C] Callout has 'Total sections:' count")
    
        if "child pages:" not in callout_content:
            errors.append("[X] Callout missing 'Child pages:' count")
        else:
            checks_passed.append("[C] Callout has 'Child pages:' count")
    
        # TODO: Re-enable bold formatting check when ready - should verify bold formatting in callout
        # RELAXED: Bold formatting check temporarily disabled
        # callout_props = callout_block.get("properties", {})
        # has_bold = "**" in callout_block.get("content", "") or (
        #     isinstance(callout_props, dict) and callout_props.get("bold", False)
        # )
    
        # Count heading2 blocks (excluding Documentation Structure and Last Reorganized)
        h2_count = len(heading2_blocks)
    
        # Verify counts in callout
        if str(h2_count) not in callout_block.get("content", ""):
            errors.append(f"[X] Callout should show count of heading_2 sections ({h2_count})")
        else:
            checks_passed.append(f"[C] Callout should show count of heading_2 sections ({h2_count})")
    
        if str(len(child_pages)) not in callout_block.get("content", ""):
            errors.append(f"[X] Callout should show count of child pages ({len(child_pages)})")
        else:
            checks_passed.append(f"[C] Callout should show count of child pages ({len(child_pages)})")
    
        # ALL requirements met!
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: create-weekly-planning-dashboard-v2
# Description: Create comprehensive Weekly Planning Dashboard with precise structure,
# daily breakdowns, and weekly metrics
# =============================================================================
def _validate_agent_create_weekly_planning_dashboard(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate Weekly Planning Dashboard creation with:
    - heading_1 '📅 Weekly Planning Dashboard'
    - heading_2 '🎯 Week Overview' with blue callout
    - heading_2 '📆 Daily Breakdown' with 5 heading_3 blocks (Monday-Friday)
    - Each day has exactly 3 unchecked to-dos with specific times
    - heading_2 '📈 Weekly Metrics' with numbered list (exact values)
    - Quote block at end
    
    Returns 1.0 only if ALL requirements are met, otherwise 0.0
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    # Query all pages and blocks from backend
    # 1. Find the 'Weekly Planning Dashboard' page
    try:
        dashboard_pages = _get_pages_by_filter(backend, {"title": "Weekly Planning Dashboard"})
        if not dashboard_pages:
            errors.append("[X] Weekly Planning Dashboard page not found")
        else:
            checks_passed.append("[C] Weekly Planning Dashboard page found")
    
        dashboard_page = dashboard_pages[0]
        dashboard_id = dashboard_page.get("_id")
    
        # 2. Get all blocks for the page
        page_blocks = _get_blocks_by_filter(backend, {"pageId": dashboard_id})
    
        if len(page_blocks) < 20:
            errors.append(f"[X] Weekly Planning Dashboard needs sufficient blocks for complete structure, found {len(page_blocks)}")
        else:
            checks_passed.append(f"[C] Weekly Planning Dashboard needs sufficient blocks for complete structure, found {len(page_blocks)}")
    
        # 3. Find key blocks
        main_heading_idx = -1
        week_overview_heading_idx = -1
        week_overview_callout_idx = -1
        daily_breakdown_heading_idx = -1
        weekly_metrics_heading_idx = -1
        quote_idx = -1
    
        day_headings = {
            "monday": -1,
            "tuesday": -1,
            "wednesday": -1,
            "thursday": -1,
            "friday": -1
        }
    
        day_todos = {
            "monday": [],
            "tuesday": [],
            "wednesday": [],
            "thursday": [],
            "friday": []
        }
    
        metrics_numbered_items = []
        current_day = None
    
        # Sort blocks by order
        blocks_by_order = sorted(
            [(block.get("order", 0), idx, block) for idx, block in enumerate(page_blocks)],
            key=lambda x: x[0]
        )
    
        for order, idx, block in blocks_by_order:
            block_type = block.get("type", "")
            block_content = block.get("content", "")
            block_props = block.get("properties", {})
        
            # Find main heading
            if block_type == "heading1" and "📅" in block_content and "weekly planning dashboard" in block_content.lower():
                main_heading_idx = idx
        
            # Find Week Overview heading
            if block_type == "heading2" and "🎯" in block_content and "week overview" in block_content.lower():
                week_overview_heading_idx = idx
        
            # Find Daily Breakdown heading
            if block_type == "heading2" and "📆" in block_content and "daily breakdown" in block_content.lower():
                daily_breakdown_heading_idx = idx
        
            # Find Weekly Metrics heading
            if block_type == "heading2" and "📈" in block_content and "weekly metrics" in block_content.lower():
                weekly_metrics_heading_idx = idx
        
            # Find day headings
            if block_type == "heading3":
                content_lower = block_content.lower()
                if "🌅" in block_content and "monday" in content_lower:
                    day_headings["monday"] = idx
                    current_day = "monday"
                elif "tuesday" in content_lower:
                    day_headings["tuesday"] = idx
                    current_day = "tuesday"
                elif "wednesday" in content_lower:
                    day_headings["wednesday"] = idx
                    current_day = "wednesday"
                elif "thursday" in content_lower:
                    day_headings["thursday"] = idx
                    current_day = "thursday"
                elif "🌙" in block_content and "friday" in content_lower:
                    day_headings["friday"] = idx
                    current_day = "friday"
                else:
                    current_day = None
        
            # Find callout after Week Overview
            if block_type == "callout":
                if week_overview_heading_idx != -1 and idx > week_overview_heading_idx:
                    if daily_breakdown_heading_idx == -1 or idx < daily_breakdown_heading_idx:
                        if week_overview_callout_idx == -1:
                            callout_props = block.get("properties", {})
                            bg_color = callout_props.get("backgroundColor", "") if isinstance(callout_props, dict) else ""
                            icon = callout_props.get("icon", "") if isinstance(callout_props, dict) else ""
                            if "blue" in bg_color.lower() and "📌" in icon:
                                week_overview_callout_idx = idx
        
            # Find todos under each day
            if block_type == "todo" and current_day:
                checked = block_props.get("checked", False) if isinstance(block_props, dict) else False
                if not checked:  # Should be unchecked
                    day_todos[current_day].append({
                        "idx": idx,
                        "content": block_content,
                        "checked": checked
                    })
        
            # Find numbered list items after Weekly Metrics
            if block_type == "numberedList":
                if weekly_metrics_heading_idx != -1 and idx > weekly_metrics_heading_idx:
                    metrics_numbered_items.append({
                        "idx": idx,
                        "content": block_content
                    })
        
            # Find quote block
            if block_type == "quote":
                if "success" in block_content.lower():
                    quote_idx = idx
    
        # 4. Validate main heading
        if main_heading_idx == -1:
            errors.append("[X] heading_1 '📅 Weekly Planning Dashboard' not found")
        else:
            checks_passed.append("[C] heading_1 '📅 Weekly Planning Dashboard' found")
    
        # 5. Validate Week Overview section
        if week_overview_heading_idx == -1:
            errors.append("[X] heading_2 '🎯 Week Overview' not found")
        else:
            checks_passed.append("[C] heading_2 '🎯 Week Overview' found")
    
        if week_overview_callout_idx == -1:
            errors.append("[X] Blue callout with '📌' icon not found after Week Overview heading")
        else:
            checks_passed.append("[C] Blue callout with '📌' icon found after Week Overview heading")
    
        # Validate callout content
        callout_block = page_blocks[week_overview_callout_idx]
        callout_content = callout_block.get("content", "").lower()
    
        if "plan your week effectively" not in callout_content:
            errors.append(f"[X] Callout should contain 'Plan your week effectively with clear priorities and time blocks.', found: '{callout_block.get('content', '')}'")
        else:
            checks_passed.append(f"[C] Callout should contain 'Plan your week effectively with clear priorities and time blocks.', found: '{callout_block.get('content', '')}'")
    
        # 6. Validate Daily Breakdown section
        if daily_breakdown_heading_idx == -1:
            errors.append("[X] heading_2 '📆 Daily Breakdown' not found")
        else:
            checks_passed.append("[C] heading_2 '📆 Daily Breakdown' found")
    
        # 7. Validate all 5 day headings exist
        missing_days = [day for day, idx in day_headings.items() if idx == -1]
        if missing_days:
            errors.append(f"[X] Missing day headings for: {missing_days}")
        else:
            checks_passed.append(f"[C] has day headings for: {missing_days}")
    
        # 8. Validate each day has exactly 3 unchecked todos with specific content
        required_todos = {
            "morning standup": "9:00 AM",
            "focus time block": "10:00 AM - 12:00 PM",
            "progress review": "4:30 PM"
        }
    
        for day, todos in day_todos.items():
            if len(todos) < 3:
                errors.append(f"[X] {day.capitalize()} should have exactly 3 unchecked to-dos, found {len(todos)}")
            else:
                checks_passed.append(f"[C] {day.capitalize()} should have exactly 3 unchecked to-dos, found {len(todos)}")
        
            # Check for required todos
            todos_text = " ".join([t["content"].lower() for t in todos[:3]])
        
            for todo_name, time in required_todos.items():
                if todo_name not in todos_text:
                    errors.append(f"[X] {day.capitalize()} missing required to-do containing '{todo_name}'")
                else:
                    checks_passed.append(f"[C] {day.capitalize()} has required to-do containing '{todo_name}'")
                if time.lower() not in todos_text:
                    errors.append(f"[X] {day.capitalize()} to-do should contain time '{time}'")
                else:
                    checks_passed.append(f"[C] {day.capitalize()} to-do should contain time '{time}'")
    
        # 9. Validate Weekly Metrics section
        if weekly_metrics_heading_idx == -1:
            errors.append("[X] heading_2 '📈 Weekly Metrics' not found")
        else:
            checks_passed.append("[C] heading_2 '📈 Weekly Metrics' found")
    
        if len(metrics_numbered_items) < 3:
            errors.append(f"[X] Weekly Metrics should have numbered list with 3 items, found {len(metrics_numbered_items)}")
        else:
            checks_passed.append(f"[C] Weekly Metrics should have numbered list with 3 items, found {len(metrics_numbered_items)}")
    
        # Validate specific metrics values
        metrics_text = " ".join([item["content"] for item in metrics_numbered_items])
    
        if "total planned activities: 15" not in metrics_text.lower():
            errors.append("[X] Weekly Metrics missing '1. Total planned activities: 15'")
        else:
            checks_passed.append("[C] Weekly Metrics has '1. Total planned activities: 15'")
    
        if "meetings scheduled: 5" not in metrics_text.lower():
            errors.append("[X] Weekly Metrics missing '2. Meetings scheduled: 5'")
        else:
            checks_passed.append("[C] Weekly Metrics has '2. Meetings scheduled: 5'")
    
        if "focus time hours: 10" not in metrics_text.lower():
            errors.append("[X] Weekly Metrics missing '3. Focus time hours: 10'")
        else:
            checks_passed.append("[C] Weekly Metrics has '3. Focus time hours: 10'")
    
        # 10. Validate quote block at end
        if quote_idx == -1:
            errors.append("[X] Quote block not found at end")
        else:
            checks_passed.append("[C] Quote block found at end")
    
        quote_block = page_blocks[quote_idx]
        quote_content = quote_block.get("content", "").lower()
    
        if "success is the sum of small efforts" not in quote_content:
            errors.append(f"[X] Quote block should contain 'Success is the sum of small efforts repeated day in and day out.', found: '{quote_block.get('content', '')}'")
        else:
            checks_passed.append(f"[C] Quote block should contain 'Success is the sum of small efforts repeated day in and day out.', found: '{quote_block.get('content', '')}'")
    
        # ALL requirements met!
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: create-feature-requests-prioritization-system-v2
# Description: Create advanced prioritization system on Feature Requests page
# with priority matrix, callouts, and analytics
# =============================================================================
def _validate_agent_create_feature_requests_prioritization_system(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate Feature Requests prioritization system with:
    - heading_2 '🎯 Priority Matrix' at beginning
    - 3 heading_3 blocks: '🔴 Critical Priority (P0)', '🟡 High Priority (P1)', '🟢 Normal Priority (P2)'
    - Callouts with matching background colors and descriptions
    - Each priority has exactly 3 unchecked to-dos with specific format
    - heading_2 '📊 Request Analytics' with paragraph and bulleted list
    - Quote block at end
    
    Returns 1.0 only if ALL requirements are met, otherwise 0.0
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Find the 'Feature Requests' page
    try:
        feature_pages = _get_pages_by_filter(backend, {"title": "Feature Requests"})
        if not feature_pages:
            errors.append("[X] Feature Requests page not found")
        else:
            checks_passed.append("[C] Feature Requests page found")
    
        feature_page = feature_pages[0]
        feature_id = feature_page.get("_id")
    
        # 2. Get all blocks for the page
        page_blocks = _get_blocks_by_filter(backend, {"pageId": feature_id})
    
        if len(page_blocks) < 20:
            errors.append(f"[X] Feature Requests needs sufficient blocks for prioritization system, found {len(page_blocks)}")
        else:
            checks_passed.append(f"[C] Feature Requests needs sufficient blocks for prioritization system, found {len(page_blocks)}")
    
        # 3. Find key blocks
        priority_matrix_heading_idx = -1
        p0_heading_idx = -1
        p1_heading_idx = -1
        p2_heading_idx = -1
    
        p0_callout_idx = -1
        p1_callout_idx = -1
        p2_callout_idx = -1
    
        p0_todos = []
        p1_todos = []
        p2_todos = []
    
        analytics_heading_idx = -1
        analytics_paragraph_idx = -1
        analytics_bullets = []
    
        quote_idx = -1
    
        current_priority = None
    
        # Sort blocks by order
        blocks_by_order = sorted(
            [(block.get("order", 0), idx, block) for idx, block in enumerate(page_blocks)],
            key=lambda x: x[0]
        )
    
        for order, idx, block in blocks_by_order:
            block_type = block.get("type", "")
            block_content = block.get("content", "")
            block_props = block.get("properties", {})
        
            # Find Priority Matrix heading
            if block_type == "heading2" and "🎯" in block_content and "priority matrix" in block_content.lower():
                priority_matrix_heading_idx = idx
        
            # Find priority level headings
            if block_type == "heading3":
                content_lower = block_content.lower()
                if "🔴" in block_content and "critical" in content_lower and "p0" in content_lower:
                    p0_heading_idx = idx
                    current_priority = "p0"
                elif "🟡" in block_content and "high" in content_lower and "p1" in content_lower:
                    p1_heading_idx = idx
                    current_priority = "p1"
                elif "🟢" in block_content and "normal" in content_lower and "p2" in content_lower:
                    p2_heading_idx = idx
                    current_priority = "p2"
                else:
                    current_priority = None
        
            # Find Request Analytics heading
            if block_type == "heading2" and "📊" in block_content and "request analytics" in block_content.lower():
                analytics_heading_idx = idx
                current_priority = None
        
            # Find callouts for each priority
            if block_type == "callout":
                callout_props = block.get("properties", {})
                bg_color = callout_props.get("backgroundColor", "") if isinstance(callout_props, dict) else ""
            
                # P0 callout (red background)
                if "red" in bg_color.lower():
                    if p0_heading_idx != -1 and idx > p0_heading_idx:
                        if p1_heading_idx == -1 or idx < p1_heading_idx:
                            if p0_callout_idx == -1:
                                p0_callout_idx = idx
            
                # P1 callout (yellow background)
                elif "yellow" in bg_color.lower():
                    if p1_heading_idx != -1 and idx > p1_heading_idx:
                        if p2_heading_idx == -1 or idx < p2_heading_idx:
                            if p1_callout_idx == -1:
                                p1_callout_idx = idx
            
                # P2 callout (green background)
                elif "green" in bg_color.lower():
                    if p2_heading_idx != -1 and idx > p2_heading_idx:
                        if analytics_heading_idx == -1 or idx < analytics_heading_idx:
                            if p2_callout_idx == -1:
                                p2_callout_idx = idx
        
            # Find todos under each priority
            if block_type == "todo" and current_priority:
                checked = block_props.get("checked", False) if isinstance(block_props, dict) else False
                if not checked:  # Should be unchecked
                    if current_priority == "p0":
                        p0_todos.append({"idx": idx, "content": block_content})
                    elif current_priority == "p1":
                        p1_todos.append({"idx": idx, "content": block_content})
                    elif current_priority == "p2":
                        p2_todos.append({"idx": idx, "content": block_content})
        
            # Find analytics paragraph
            if block_type == "paragraph":
                if analytics_heading_idx != -1 and idx > analytics_heading_idx:
                    if analytics_paragraph_idx == -1:
                        if "total features in queue: 9" in block_content.lower():
                            analytics_paragraph_idx = idx
        
            # Find analytics bullets
            if block_type == "bulletedList":
                if analytics_heading_idx != -1 and idx > analytics_heading_idx:
                    if "p0" in block_content.lower() or "p1" in block_content.lower() or "p2" in block_content.lower():
                        if "33%" in block_content:
                            analytics_bullets.append({"idx": idx, "content": block_content})
        
            # Find quote block
            if block_type == "quote":
                if "customer feedback drives" in block_content.lower():
                    quote_idx = idx
    
        # 4. Validate Priority Matrix heading
        if priority_matrix_heading_idx == -1:
            errors.append("[X] heading_2 '🎯 Priority Matrix' not found at beginning")
        else:
            checks_passed.append("[C] heading_2 '🎯 Priority Matrix' found at beginning")
    
        if priority_matrix_heading_idx > 3:
            errors.append(f"[X] Priority Matrix should be at beginning, found at idx {priority_matrix_heading_idx}")
        else:
            checks_passed.append(f"[C] Priority Matrix should be at beginning, found at idx {priority_matrix_heading_idx}")
    
        # 5. Validate all three priority headings
        if p0_heading_idx == -1:
            errors.append("[X] heading_3 '🔴 Critical Priority (P0)' not found")
        else:
            checks_passed.append("[C] heading_3 '🔴 Critical Priority (P0)' found")
    
        if p1_heading_idx == -1:
            errors.append("[X] heading_3 '🟡 High Priority (P1)' not found")
        else:
            checks_passed.append("[C] heading_3 '🟡 High Priority (P1)' found")
    
        if p2_heading_idx == -1:
            errors.append("[X] heading_3 '🟢 Normal Priority (P2)' not found")
        else:
            checks_passed.append("[C] heading_3 '🟢 Normal Priority (P2)' found")
    
        # 6. Validate heading order
        if not (priority_matrix_heading_idx < p0_heading_idx < p1_heading_idx < p2_heading_idx):
            errors.append(f"[X] Priority headings not in correct order: Matrix({priority_matrix_heading_idx}) < P0({p0_heading_idx}) < P1({p1_heading_idx}) < P2({p2_heading_idx})")
        else:
            checks_passed.append(f"[C] Priority headings in correct order: Matrix({priority_matrix_heading_idx}) < P0({p0_heading_idx}) < P1({p1_heading_idx}) < P2({p2_heading_idx})")
    
        # 7. Validate callouts with correct colors and descriptions
        if p0_callout_idx == -1:
            errors.append("[X] Red background callout not found after P0 heading")
        else:
            checks_passed.append("[C] Red background callout found after P0 heading")
    
        p0_callout = page_blocks[p0_callout_idx]
        p0_content = p0_callout.get("content", "").lower()
        if "blocking major customer deals" not in p0_content and "revenue loss" not in p0_content:
            errors.append(f"[X] P0 callout should describe 'Features blocking major customer deals or causing revenue loss', found: '{p0_callout.get('content', '')}'")
        else:
            checks_passed.append(f"[C] P0 callout should describe 'Features blocking major customer deals or causing revenue loss', found: '{p0_callout.get('content', '')}'")
    
        if p1_callout_idx == -1:
            errors.append("[X] Yellow background callout not found after P1 heading")
        else:
            checks_passed.append("[C] Yellow background callout found after P1 heading")
    
        p1_callout = page_blocks[p1_callout_idx]
        p1_content = p1_callout.get("content", "").lower()
        if "high-impact" not in p1_content and "enterprise" not in p1_content:
            errors.append(f"[X] P1 callout should describe 'High-impact improvements requested by multiple enterprise clients', found: '{p1_callout.get('content', '')}'")
        else:
            checks_passed.append(f"[C] P1 callout should describe 'High-impact improvements requested by multiple enterprise clients', found: '{p1_callout.get('content', '')}'")
    
        if p2_callout_idx == -1:
            errors.append("[X] Green background callout not found after P2 heading")
        else:
            checks_passed.append("[C] Green background callout found after P2 heading")
    
        p2_callout = page_blocks[p2_callout_idx]
        p2_content = p2_callout.get("content", "").lower()
        if "quality of life" not in p2_content and "minor enhancements" not in p2_content:
            errors.append(f"[X] P2 callout should describe 'Quality of life improvements and minor enhancements', found: '{p2_callout.get('content', '')}'")
        else:
            checks_passed.append(f"[C] P2 callout should describe 'Quality of life improvements and minor enhancements', found: '{p2_callout.get('content', '')}'")
    
        # 8. Validate each priority has exactly 3 todos with correct format
        if len(p0_todos) < 3:
            errors.append(f"[X] P0 section should have exactly 3 unchecked to-dos, found {len(p0_todos)}")
        else:
            checks_passed.append(f"[C] P0 section should have exactly 3 unchecked to-dos, found {len(p0_todos)}")
    
        if len(p1_todos) < 3:
            errors.append(f"[X] P1 section should have exactly 3 unchecked to-dos, found {len(p1_todos)}")
        else:
            checks_passed.append(f"[C] P1 section should have exactly 3 unchecked to-dos, found {len(p1_todos)}")
    
        if len(p2_todos) < 3:
            errors.append(f"[X] P2 section should have exactly 3 unchecked to-dos, found {len(p2_todos)}")
        else:
            checks_passed.append(f"[C] P2 section should have exactly 3 unchecked to-dos, found {len(p2_todos)}")
    
        # Validate todo format contains "customers requesting"
        for priority_name, todos in [("P0", p0_todos[:3]), ("P1", p1_todos[:3]), ("P2", p2_todos[:3])]:
            for todo in todos:
                content_lower = todo["content"].lower()
                if "customer" not in content_lower:
                    errors.append(f"[X] {priority_name} to-dos should follow format '[Feature Name] - [Customer Count] customers requesting'")
                else:
                    checks_passed.append(f"[C] {priority_name} to-dos should follow format '[Feature Name] - [Customer Count] customers requesting'")
    
        # 9. Validate Request Analytics section
        if analytics_heading_idx == -1:
            errors.append("[X] heading_2 '📊 Request Analytics' not found")
        else:
            checks_passed.append("[C] heading_2 '📊 Request Analytics' found")
    
        if analytics_paragraph_idx == -1:
            errors.append("[X] Analytics paragraph showing 'Total features in queue: 9' not found")
        else:
            checks_passed.append("[C] Analytics paragraph showing 'Total features in queue: 9' found")
    
        if len(analytics_bullets) < 3:
            errors.append(f"[X] Analytics should have bulleted list with 3 items (P0, P1, P2 with 33%), found {len(analytics_bullets)}")
        else:
            checks_passed.append(f"[C] Analytics should have bulleted list with 3 items (P0, P1, P2 with 33%), found {len(analytics_bullets)}")
    
        # Validate each priority is represented in bullets
        bullets_text = " ".join([b["content"].lower() for b in analytics_bullets])
    
        if "p0" not in bullets_text or "3" not in bullets_text:
            errors.append("[X] Analytics bullets missing '• P0 Features: 3 (33%)'")
        else:
            checks_passed.append("[C] Analytics bullets has '• P0 Features: 3 (33%)'")
    
        if "p1" not in bullets_text:
            errors.append("[X] Analytics bullets missing '• P1 Features: 3 (33%)'")
        else:
            checks_passed.append("[C] Analytics bullets has '• P1 Features: 3 (33%)'")
    
        if "p2" not in bullets_text:
            errors.append("[X] Analytics bullets missing '• P2 Features: 3 (33%)'")
        else:
            checks_passed.append("[C] Analytics bullets has '• P2 Features: 3 (33%)'")
    
        # 10. Validate quote block
        if quote_idx == -1:
            errors.append("[X] Quote block not found at end")
        else:
            checks_passed.append("[C] Quote block found at end")
    
        quote_block = page_blocks[quote_idx]
        quote_content = quote_block.get("content", "").lower()
    
        if "customer feedback drives our product roadmap" not in quote_content:
            errors.append(f"[X] Quote should contain 'Customer feedback drives our product roadmap.', found: '{quote_block.get('content', '')}'")
        else:
            checks_passed.append(f"[C] Quote should contain 'Customer feedback drives our product roadmap.', found: '{quote_block.get('content', '')}'")
    
        # ALL requirements met!
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Export Registry
# =============================================================================

# =============================================================================
# Task: add-progress-tracker-to-onboarding-guide-v2
# Description: Insert progress tracking section after First Day Tasks but before First Week Goals
# =============================================================================
def _validate_agent_add_progress_tracker_to_onboarding_guide(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate progress tracker section insertion with:
    - heading_3 'Progress Tracker' appears after First Day Tasks (order > 5) but before First Week Goals (order < 6)
    - Green callout with ✅ icon and exact text 'Track your onboarding progress below'
    - Exactly 3 unchecked todos with specified emojis and text
    
    Returns 1.0 only if ALL requirements are met, otherwise 0.0
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Find the 'Onboarding Guide' page
    try:
        onboarding_pages = _get_pages_by_filter(backend, {"title": "Onboarding Guide"})
        if not onboarding_pages:
            errors.append("[X] Onboarding Guide page not found")
        else:
            checks_passed.append("[C] Onboarding Guide page found")
    
        onboarding_page = onboarding_pages[0]
        onboarding_id = onboarding_page.get("_id")
    
        # 2. Get all blocks for the page
        page_blocks = _get_blocks_by_filter(backend, {"pageId": onboarding_id})
    
        if len(page_blocks) < 5:
            errors.append(f"[X] Onboarding Guide needs sufficient blocks, found {len(page_blocks)}")
        else:
            checks_passed.append(f"[C] Onboarding Guide needs sufficient blocks, found {len(page_blocks)}")
    
        # 3. Find key sections
        first_day_tasks_end_order = -1
        first_week_goals_order = -1
        progress_tracker_heading_idx = -1
        progress_tracker_heading_order = -1
        green_callout_idx = -1
        todo_blocks = []
    
        # First, find First Day Tasks section end (last numbered list item)
        first_day_heading_idx = -1
        for idx, block in enumerate(page_blocks):
            block_type = block.get("type", "")
            block_content = block.get("content", "")
        
            if block_type in ["heading2", "heading3"] and "first day" in block_content.lower():
                first_day_heading_idx = idx
    
        # Find last numbered list item after First Day Tasks heading (stop at next heading)
        if first_day_heading_idx != -1:
            for idx, block in enumerate(page_blocks):
                if idx > first_day_heading_idx:
                    block_type = block.get("type", "")
                    block_order = block.get("order", 0)
                    # Stop when we hit another heading
                    if block_type in ["heading2", "heading3"]:
                        break
                    if block_type == "numberedList":
                        first_day_tasks_end_order = block_order
    
        # Sort blocks by order for sequential validation
        blocks_by_order = sorted(
            [(block.get("order", 0), idx, block) for idx, block in enumerate(page_blocks)],
            key=lambda x: x[0]
        )
    
        for order, idx, block in blocks_by_order:
            block_type = block.get("type", "")
            block_content = block.get("content", "")
            block_properties = block.get("properties", {})
        
            # Find Progress Tracker heading
            if block_type == "heading3" and "progress tracker" in block_content.lower():
                progress_tracker_heading_idx = idx
                progress_tracker_heading_order = order
        
            # Find First Week Goals heading
            if block_type in ["heading2", "heading3"] and "first week" in block_content.lower() and "goals" in block_content.lower():
                first_week_goals_order = order
        
            # Find green callout after Progress Tracker
            if block_type == "callout":
                if progress_tracker_heading_idx != -1 and idx > progress_tracker_heading_idx:
                    bg_color = block_properties.get("backgroundColor", "") if isinstance(block_properties, dict) else ""
                    icon = block_properties.get("icon", "") if isinstance(block_properties, dict) else ""
                    if "green" in bg_color.lower() and "✅" in str(icon):
                        if green_callout_idx == -1:
                            green_callout_idx = idx
        
            # Collect todo blocks after callout
            if block_type == "todo":
                if green_callout_idx != -1 and idx > green_callout_idx:
                    # Only collect todos before the next major heading
                    if first_week_goals_order == -1 or order < first_week_goals_order:
                        is_checked = block_properties.get("checked", False) if isinstance(block_properties, dict) else False
                        todo_blocks.append({
                            "idx": idx,
                            "content": block_content,
                            "checked": is_checked
                        })
    
        # 4. Validate Progress Tracker heading exists
        if progress_tracker_heading_idx == -1:
            errors.append("[X] heading_3 'Progress Tracker' not found")
        else:
            checks_passed.append("[C] heading_3 'Progress Tracker' found")
    
        # 5. Validate Progress Tracker is positioned correctly
        if first_day_tasks_end_order != -1 and progress_tracker_heading_order <= first_day_tasks_end_order:
            errors.append(f"[X] Progress Tracker heading should be after First Day Tasks (First Day end at order {first_day_tasks_end_order}, Progress Tracker at order {progress_tracker_heading_order})")
        else:
            checks_passed.append(f"[C] Progress Tracker heading should be after First Day Tasks (First Day end at order {first_day_tasks_end_order}, Progress Tracker at order {progress_tracker_heading_order})")
    
        if first_week_goals_order != -1 and progress_tracker_heading_order >= first_week_goals_order:
            errors.append(f"[X] Progress Tracker heading should be before First Week Goals (First Week at order {first_week_goals_order}, Progress Tracker at order {progress_tracker_heading_order})")
        else:
            checks_passed.append(f"[C] Progress Tracker heading should be before First Week Goals (First Week at order {first_week_goals_order}, Progress Tracker at order {progress_tracker_heading_order})")
    
        # 6. Validate green callout exists
        if green_callout_idx == -1:
            errors.append("[X] Green callout with ✅ icon not found after Progress Tracker heading")
        else:
            checks_passed.append("[C] Green callout with ✅ icon found after Progress Tracker heading")
    
        # 7. Validate callout text
        callout_block = page_blocks[green_callout_idx]
        callout_content = callout_block.get("content", "")
        if "track your onboarding progress below" not in callout_content.lower():
            errors.append(f"[X] Callout should contain 'Track your onboarding progress below', found: {callout_content}")
        else:
            checks_passed.append(f"[C] Callout should contain 'Track your onboarding progress below', found: {callout_content}")
    
        # 8. Validate exactly 3 todos
        if len(todo_blocks) != 3:
            errors.append(f"[X] Should have exactly 3 todo blocks after callout, found {len(todo_blocks)}")
        else:
            checks_passed.append(f"[C] Should have exactly 3 todo blocks after callout, found {len(todo_blocks)}")
    
        # 9. Validate all todos are unchecked
        checked_todos = [t for t in todo_blocks if t["checked"]]
        if checked_todos:
            errors.append(f"[X] All todos should be unchecked, found {len(checked_todos)} checked")
        else:
            checks_passed.append(f"[C] All todos should be unchecked, found {len(checked_todos)} checked")
    
        # 10. Validate todo content with emojis
        required_todos = [
            ("📧", "set up email and calendar"),
            ("🔐", "complete security training"),
            ("👋", "introduce yourself in #new-hires channel")
        ]
    
        for idx, (emoji, text_part) in enumerate(required_todos):
            if idx >= len(todo_blocks):
                errors.append(f"[X] Missing todo {idx+1}: should contain '{emoji}' and '{text_part}'")
            else:
                checks_passed.append(f"[C] has todo {idx+1}: should contain '{emoji}' and '{text_part}'")
        
            todo_content = todo_blocks[idx]["content"]
            if emoji not in todo_content:
                errors.append(f"[X] Todo {idx+1} should contain emoji '{emoji}', found: {todo_content}")
            else:
                checks_passed.append(f"[C] Todo {idx+1} should contain emoji '{emoji}', found: {todo_content}")
        
            if text_part not in todo_content.lower():
                errors.append(f"[X] Todo {idx+1} should contain text '{text_part}', found: {todo_content}")
            else:
                checks_passed.append(f"[C] Todo {idx+1} should contain text '{text_part}', found: {todo_content}")
    
        # ALL requirements met!
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: restructure-engineering-wiki-with-navigation-v2
# Description: Complex content restructuring with Quick Navigation, numbered links, and Related Resources
# =============================================================================
def _validate_agent_restructure_engineering_wiki_with_navigation(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate Engineering Wiki restructuring with:
    - Quick Navigation section at top (after main heading_1, before other content)
    - Gray callout with 'Jump to any section:' text (TODO: should check for bold formatting in future)
    - Numbered list with one item per existing heading_2 section
    - Related Resources section at end with 3 bookmark blocks
    - Divider and final paragraph showing section count (TODO: should check for italic formatting in future)
    
    Returns 1.0 only if ALL requirements are met, otherwise 0.0
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Find the 'Engineering Wiki' page
    try:
        wiki_pages = _get_pages_by_filter(backend, {"title": "Engineering Wiki"})
        if not wiki_pages:
            errors.append("[X] Engineering Wiki page not found")
        else:
            checks_passed.append("[C] Engineering Wiki page found")
    
        wiki_page = wiki_pages[0]
        wiki_id = wiki_page.get("_id")
    
        # 2. Get all blocks for the page
        page_blocks = _get_blocks_by_filter(backend, {"pageId": wiki_id})
    
        if len(page_blocks) < 5:
            errors.append(f"[X] Engineering Wiki needs sufficient blocks, found {len(page_blocks)}")
        else:
            checks_passed.append(f"[C] Engineering Wiki needs sufficient blocks, found {len(page_blocks)}")
    
        # 3. Find key elements
        main_heading_idx = -1
        quick_nav_heading_idx = -1
        quick_nav_heading_order = -1
        gray_callout_idx = -1
        quick_nav_numbered_items = []
        related_resources_heading_idx = -1
        bookmark_blocks = []
        final_divider_idx = -1
        final_paragraph_idx = -1
    
        # Count original heading_2 blocks (excluding Quick Navigation and Related Resources)
        original_heading2_blocks = []
        all_heading2_blocks = []
    
        # Sort blocks by order
        blocks_by_order = sorted(
            [(block.get("order", 0), idx, block) for idx, block in enumerate(page_blocks)],
            key=lambda x: x[0]
        )
    
        for order, idx, block in blocks_by_order:
            block_type = block.get("type", "")
            block_content = block.get("content", "")
            block_properties = block.get("properties", {})
        
            # Find main heading_1
            if block_type == "heading1":
                if main_heading_idx == -1:
                    main_heading_idx = idx
        
            # Find Quick Navigation heading
            if block_type == "heading2" and "🧭" in block_content and "quick navigation" in block_content.lower():
                quick_nav_heading_idx = idx
                quick_nav_heading_order = order
        
            # Find Related Resources heading
            if block_type == "heading2" and "📚" in block_content and "related resources" in block_content.lower():
                related_resources_heading_idx = idx
        
            # Collect all heading_2 blocks
            if block_type == "heading2":
                all_heading2_blocks.append({
                    "idx": idx,
                    "order": order,
                    "content": block_content
                })
            
                # Original sections (not Quick Nav or Related Resources)
                if "quick navigation" not in block_content.lower() and "related resources" not in block_content.lower():
                    original_heading2_blocks.append({
                        "idx": idx,
                        "order": order,
                        "content": block_content
                    })
        
            # Find gray callout after Quick Navigation
            if block_type == "callout":
                if quick_nav_heading_idx != -1 and idx > quick_nav_heading_idx:
                    bg_color = block_properties.get("backgroundColor", "") if isinstance(block_properties, dict) else ""
                    if "gray" in bg_color.lower() or "grey" in bg_color.lower():
                        if gray_callout_idx == -1:
                            gray_callout_idx = idx
        
            # Collect numbered list items after Quick Navigation
            if block_type == "numberedList":
                if quick_nav_heading_idx != -1 and idx > quick_nav_heading_idx:
                    # Should be before the first original section or Related Resources
                    if (not original_heading2_blocks or order < original_heading2_blocks[0]["order"]):
                        quick_nav_numbered_items.append({
                            "idx": idx,
                            "content": block_content
                        })
        
            # Collect bookmark blocks after Related Resources
            if block_type == "bookmark":
                if related_resources_heading_idx != -1 and idx > related_resources_heading_idx:
                    bookmark_blocks.append({
                        "idx": idx,
                        "content": block_content,
                        "properties": block_properties
                    })
        
            # Find divider near end (after Related Resources)
            if block_type == "divider":
                if related_resources_heading_idx != -1 and idx > related_resources_heading_idx:
                    if len(bookmark_blocks) >= 3:  # After the bookmark blocks
                        final_divider_idx = idx
        
            # Find final paragraph
            # TODO: Re-enable italic formatting check when ready - should verify italic formatting
            if block_type == "paragraph":
                if final_divider_idx != -1 and idx > final_divider_idx:
                    if "last updated" in block_content.lower() and "total sections" in block_content.lower():
                        final_paragraph_idx = idx
    
        # 4. Validate main heading exists
        if main_heading_idx == -1:
            errors.append("[X] Main heading_1 not found on Engineering Wiki page")
        else:
            checks_passed.append("[C] Main heading_1 found on Engineering Wiki page")
    
        # 5. Validate Quick Navigation heading exists and is positioned first
        if quick_nav_heading_idx == -1:
            errors.append("[X] heading_2 '🧭 Quick Navigation' not found")
        else:
            checks_passed.append("[C] heading_2 '🧭 Quick Navigation' found")
    
        # Quick Navigation should be right after main heading
        if quick_nav_heading_idx <= main_heading_idx:
            errors.append(f"[X] Quick Navigation should be after main heading (main at idx {main_heading_idx}, Quick Nav at idx {quick_nav_heading_idx})")
        else:
            checks_passed.append(f"[C] Quick Navigation should be after main heading (main at idx {main_heading_idx}, Quick Nav at idx {quick_nav_heading_idx})")
    
        # Quick Navigation should be before all original sections
        if original_heading2_blocks and quick_nav_heading_order >= original_heading2_blocks[0]["order"]:
            errors.append(f"[X] Quick Navigation should be before all original sections (Quick Nav order {quick_nav_heading_order}, first section order {original_heading2_blocks[0]['order']})")
        else:
            checks_passed.append(f"[C] Quick Navigation should be before all original sections (Quick Nav order {quick_nav_heading_order}, first section order {original_heading2_blocks[0]['order']})")
    
        # 6. Validate gray callout exists
        if gray_callout_idx == -1:
            errors.append("[X] Gray callout not found after Quick Navigation heading")
        else:
            checks_passed.append("[C] Gray callout found after Quick Navigation heading")
    
        # 7. Validate callout content
        # TODO: Re-enable bold formatting check when ready - should verify bold 'Jump to any section:' text
        callout_block = page_blocks[gray_callout_idx]
        callout_content = callout_block.get("content", "")
        if "jump to any section" not in callout_content.lower():
            errors.append(f"[X] Gray callout should contain 'Jump to any section:', found: {callout_content}")
        else:
            checks_passed.append(f"[C] Gray callout should contain 'Jump to any section:', found: {callout_content}")
    
        # 8. Validate numbered list items match original sections
        if len(quick_nav_numbered_items) != len(original_heading2_blocks):
            errors.append(f"[X] Quick Navigation should have {len(original_heading2_blocks)} numbered list items (one per original section), found {len(quick_nav_numbered_items)}")
        else:
            checks_passed.append(f"[C] Quick Navigation should have {len(original_heading2_blocks)} numbered list items (one per original section), found {len(quick_nav_numbered_items)}")
    
        # 9. Validate Related Resources heading exists
        if related_resources_heading_idx == -1:
            errors.append("[X] heading_2 '📚 Related Resources' not found")
        else:
            checks_passed.append("[C] heading_2 '📚 Related Resources' found")
    
        # Related Resources should be after all original sections
        if original_heading2_blocks and related_resources_heading_idx <= original_heading2_blocks[-1]["idx"]:
            errors.append(f"[X] Related Resources should be after all original sections")
        else:
            checks_passed.append(f"[C] Related Resources should be after all original sections")
    
        # 10. Validate exactly 3 bookmark blocks
        if len(bookmark_blocks) != 3:
            errors.append(f"[X] Related Resources should have exactly 3 bookmark blocks, found {len(bookmark_blocks)}")
        else:
            checks_passed.append(f"[C] Related Resources should have exactly 3 bookmark blocks, found {len(bookmark_blocks)}")
    
        # 11. Validate bookmark titles and URLs
        required_bookmarks = [
            ("api documentation", "/api-docs"),
            ("design system", "/design-system"),
            ("team directory", "/team-directory")
        ]
    
        for idx, (title_part, url_part) in enumerate(required_bookmarks):
            if idx >= len(bookmark_blocks):
                errors.append(f"[X] Missing bookmark {idx+1}: should link to {url_part}")
            else:
                checks_passed.append(f"[C] has bookmark {idx+1}: should link to {url_part}")
        
            bookmark_content = bookmark_blocks[idx]["content"].lower()
            bookmark_props = bookmark_blocks[idx]["properties"]
            bookmark_url = bookmark_props.get("url", "") if isinstance(bookmark_props, dict) else ""
        
            if title_part not in bookmark_content and title_part not in bookmark_url.lower():
                errors.append(f"[X] Bookmark {idx+1} should reference '{title_part}', found: {bookmark_content}")
            else:
                checks_passed.append(f"[C] Bookmark {idx+1} should reference '{title_part}', found: {bookmark_content}")
        
            if url_part not in bookmark_url.lower():
                errors.append(f"[X] Bookmark {idx+1} should link to '{url_part}', found URL: {bookmark_url}")
            else:
                checks_passed.append(f"[C] Bookmark {idx+1} should link to '{url_part}', found URL: {bookmark_url}")
    
        # 12. Validate final divider exists
        if final_divider_idx == -1:
            errors.append("[X] Divider not found after Related Resources section")
        else:
            checks_passed.append("[C] Divider found after Related Resources section")
    
        # 13. Validate final paragraph exists
        if final_paragraph_idx == -1:
            errors.append("[X] Final paragraph with 'Last updated' and 'Total sections' not found")
        else:
            checks_passed.append("[C] Final paragraph with 'Last updated' and 'Total sections' found")
    
        # 14. Validate section count in final paragraph
        total_heading2_count = len(all_heading2_blocks)
        final_para_content = page_blocks[final_paragraph_idx].get("content", "")
    
        # The paragraph should mention the correct count
        if str(total_heading2_count) not in final_para_content:
            errors.append(f"[X] Final paragraph should show total sections count of {total_heading2_count}, found: {final_para_content}")
        else:
            checks_passed.append(f"[C] Final paragraph should show total sections count of {total_heading2_count}, found: {final_para_content}")
    
        # ALL requirements met!
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: add-revision-history-to-prd-v2
# Description: Add Revision History section after Overview - Part 3 with callout and dates
# =============================================================================
def _validate_agent_add_revision_history_to_prd(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate Revision History section with:
    - heading_2 '🔄 Revision History' after 'Overview - Part 3'
    - Gray callout with 📅 icon containing heading_3 'Latest Updates'
    - Numbered list inside callout with 3 specific dates and updates
    - Divider after callout
    - Paragraph about version control (TODO: should check for italic formatting in future)
    
    Returns 1.0 only if ALL requirements are met, otherwise 0.0
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Find the 'Comprehensive Product Requirements Document' page
    try:
        prd_page = _find_page_by_title(final_state_backend, "Comprehensive Product Requirements Document")
        if not prd_page:
            # Try alternative names
            prd_page = _find_page_by_title(final_state_backend, "Product Requirements Document")
        if not prd_page:
            errors.append("[X] Comprehensive Product Requirements Document page not found")
        else:
            checks_passed.append("[C] Comprehensive Product Requirements Document page found")
    
        prd_id = prd_page.get("_id")
    
        # 2. Get all blocks for the page
        page_blocks = _get_blocks_for_page(final_state_backend, prd_id)
    
        if len(page_blocks) < 5:
            errors.append(f"[X] Product Requirements Document needs sufficient blocks, found {len(page_blocks)}")
        else:
            checks_passed.append(f"[C] Product Requirements Document needs sufficient blocks, found {len(page_blocks)}")
    
        # 3. Find key sections
        overview_part3_idx = -1
        overview_part3_order = -1
        revision_history_heading_idx = -1
        revision_history_heading_order = -1
        gray_callout_idx = -1
        latest_updates_h3_idx = -1
        numbered_items_in_callout = []
        divider_after_callout_idx = -1
        final_paragraph_idx = -1
    
        # Sort blocks by order
        blocks_by_order = sorted(
            [(block.get("order", 0), idx, block) for idx, block in enumerate(page_blocks)],
            key=lambda x: x[0]
        )
    
        for order, idx, block in blocks_by_order:
            block_type = block.get("type", "")
            block_content = block.get("content", "")
            block_properties = block.get("properties", {})
        
            # Find Overview - Part 3 heading
            if block_type in ["heading2", "heading3"]:
                if "overview" in block_content.lower() and "part 3" in block_content.lower():
                    overview_part3_idx = idx
                    overview_part3_order = order
        
            # Find Revision History heading
            if block_type == "heading2" and "🔄" in block_content and "revision history" in block_content.lower():
                revision_history_heading_idx = idx
                revision_history_heading_order = order
        
            # Find gray callout after Revision History
            if block_type == "callout":
                if revision_history_heading_idx != -1 and idx > revision_history_heading_idx:
                    bg_color = block_properties.get("backgroundColor", "") if isinstance(block_properties, dict) else ""
                    icon = block_properties.get("icon", "") if isinstance(block_properties, dict) else ""
                    if ("gray" in bg_color.lower() or "grey" in bg_color.lower()) and "📅" in str(icon):
                        if gray_callout_idx == -1:
                            gray_callout_idx = idx
        
            # Find Latest Updates heading_3 (should be inside callout)
            if block_type == "heading3" and "latest updates" in block_content.lower():
                if gray_callout_idx != -1:
                    latest_updates_h3_idx = idx
        
            # Collect numbered list items in callout
            if block_type == "numberedList":
                if gray_callout_idx != -1 and idx > gray_callout_idx:
                    # Should be before divider
                    if divider_after_callout_idx == -1:
                        numbered_items_in_callout.append({
                            "idx": idx,
                            "content": block_content
                        })
        
            # Find divider after callout
            if block_type == "divider":
                if gray_callout_idx != -1 and idx > gray_callout_idx:
                    if len(numbered_items_in_callout) > 0:
                        if divider_after_callout_idx == -1:
                            divider_after_callout_idx = idx
        
            # Find final paragraph about version control
            # TODO: Re-enable italic formatting check when ready - should verify italic formatting
            if block_type == "paragraph":
                if divider_after_callout_idx != -1 and idx > divider_after_callout_idx:
                    if "version control" in block_content.lower():
                        if final_paragraph_idx == -1:
                            final_paragraph_idx = idx
    
        # 4. Validate Overview - Part 3 exists
        if overview_part3_idx == -1:
            errors.append("[X] Overview - Part 3 heading not found")
        else:
            checks_passed.append("[C] Overview - Part 3 heading found")
    
        # 5. Validate Revision History heading exists
        if revision_history_heading_idx == -1:
            errors.append("[X] heading_2 '🔄 Revision History' not found")
        else:
            checks_passed.append("[C] heading_2 '🔄 Revision History' found")
    
        # 6. Validate Revision History is after Overview - Part 3
        if revision_history_heading_order <= overview_part3_order:
            errors.append(f"[X] Revision History should be after Overview - Part 3 (Overview at order {overview_part3_order}, Revision at order {revision_history_heading_order})")
        else:
            checks_passed.append(f"[C] Revision History should be after Overview - Part 3 (Overview at order {overview_part3_order}, Revision at order {revision_history_heading_order})")
    
        # 7. Validate gray callout exists
        if gray_callout_idx == -1:
            errors.append("[X] Gray callout with 📅 icon not found after Revision History heading")
        else:
            checks_passed.append("[C] Gray callout with 📅 icon found after Revision History heading")
    
        # 8. Validate Latest Updates heading_3 exists inside callout
        if latest_updates_h3_idx == -1:
            errors.append("[X] heading_3 'Latest Updates' not found inside callout")
        else:
            checks_passed.append("[C] heading_3 'Latest Updates' found inside callout")
    
        # 9. Validate exactly 3 numbered list items in callout
        if len(numbered_items_in_callout) != 3:
            errors.append(f"[X] Callout should contain exactly 3 numbered list items, found {len(numbered_items_in_callout)}")
        else:
            checks_passed.append(f"[C] Callout should contain exactly 3 numbered list items, found {len(numbered_items_in_callout)}")
    
        # 10. Validate dated entries
        required_dates = ["2024-02-15", "2024-02-10", "2024-02-05"]
        required_texts = [
            "api integration requirements",
            "performance benchmarks",
            "initial draft"
        ]
    
        for idx, (date, text) in enumerate(zip(required_dates, required_texts)):
            if idx >= len(numbered_items_in_callout):
                errors.append(f"[X] Missing numbered item {idx+1}")
            else:
                checks_passed.append(f"[C] has numbered item {idx+1}")
        
            item_content = numbered_items_in_callout[idx]["content"].lower()
            if date not in item_content:
                errors.append(f"[X] Numbered item {idx+1} should contain date '{date}', found: {numbered_items_in_callout[idx]['content']}")
            else:
                checks_passed.append(f"[C] Numbered item {idx+1} should contain date '{date}', found: {numbered_items_in_callout[idx]['content']}")
        
            if text not in item_content:
                errors.append(f"[X] Numbered item {idx+1} should contain '{text}', found: {numbered_items_in_callout[idx]['content']}")
            else:
                checks_passed.append(f"[C] Numbered item {idx+1} should contain '{text}', found: {numbered_items_in_callout[idx]['content']}")
    
        # 11. Validate divider exists
        if divider_after_callout_idx == -1:
            errors.append("[X] Divider not found after callout")
        else:
            checks_passed.append("[C] Divider found after callout")
    
        # 12. Validate final paragraph exists
        # TODO: Re-enable italic formatting check when ready - should verify italic formatting
        if final_paragraph_idx == -1:
            errors.append("[X] Final paragraph about version control not found")
        else:
            checks_passed.append("[C] Final paragraph about version control found")
    
        # ALL requirements met!
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: add-executive-summary-to-prd-v2
# Description: Add Executive Summary section between main title and Overview with counts
# =============================================================================
def _validate_agent_add_executive_summary_to_prd(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate Executive Summary section with:
    - heading_2 '📋 Executive Summary' between main title and Overview heading_2
    - Blue callout with 🎯 icon containing accurate counts of heading_2 and paragraph blocks
    - Divider
    - Paragraph with version 2.0 and date (TODO: should check for bold date formatting in future)
    
    Returns 1.0 only if ALL requirements are met, otherwise 0.0
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Find the 'Product Requirements Document' page
    try:
        prd_pages = _get_pages_by_filter(backend, {"title": "Product Requirements Document"})
        if not prd_pages:
            prd_pages = _get_pages_by_filter(backend, {"title": "Comprehensive Product Requirements Document"})
        if not prd_pages:
            errors.append("[X] Product Requirements Document page not found")
        else:
            checks_passed.append("[C] Product Requirements Document page found")
    
        prd_page = prd_pages[0]
        prd_id = prd_page.get("_id")
    
        # 2. Get all blocks for the page
        page_blocks = _get_blocks_by_filter(backend, {"pageId": prd_id})
    
        if len(page_blocks) < 5:
            errors.append(f"[X] Product Requirements Document needs sufficient blocks, found {len(page_blocks)}")
        else:
            checks_passed.append(f"[C] Product Requirements Document needs sufficient blocks, found {len(page_blocks)}")
    
        # 3. Count heading_2 and paragraph blocks
        heading2_count = sum(1 for b in page_blocks if b.get("type") == "heading2")
        paragraph_count = sum(1 for b in page_blocks if b.get("type") == "paragraph")
    
        # 4. Find key sections
        main_title_idx = -1
        main_title_order = -1
        exec_summary_heading_idx = -1
        exec_summary_heading_order = -1
        overview_heading_idx = -1
        overview_heading_order = -1
        blue_callout_idx = -1
        divider_idx = -1
        version_paragraph_idx = -1
    
        # Sort blocks by order
        blocks_by_order = sorted(
            [(block.get("order", 0), idx, block) for idx, block in enumerate(page_blocks)],
            key=lambda x: x[0]
        )
    
        for order, idx, block in blocks_by_order:
            block_type = block.get("type", "")
            block_content = block.get("content", "")
            block_properties = block.get("properties", {})
        
            # Find main title (heading_1)
            if block_type == "heading1":
                if "product requirements" in block_content.lower():
                    if main_title_idx == -1:
                        main_title_idx = idx
                        main_title_order = order
        
            # Find Executive Summary heading
            if block_type == "heading2" and "📋" in block_content and "executive summary" in block_content.lower():
                exec_summary_heading_idx = idx
                exec_summary_heading_order = order
        
            # Find Overview heading
            if block_type == "heading2" and "overview" in block_content.lower():
                # Exclude Executive Summary itself
                if "executive summary" not in block_content.lower():
                    if overview_heading_idx == -1:
                        overview_heading_idx = idx
                        overview_heading_order = order
        
            # Find blue callout after Executive Summary
            if block_type == "callout":
                if exec_summary_heading_idx != -1 and idx > exec_summary_heading_idx:
                    bg_color = block_properties.get("backgroundColor", "") if isinstance(block_properties, dict) else ""
                    icon = block_properties.get("icon", "") if isinstance(block_properties, dict) else ""
                    if "blue" in bg_color.lower() and "🎯" in str(icon):
                        if blue_callout_idx == -1:
                            blue_callout_idx = idx
        
            # Find divider after callout
            if block_type == "divider":
                if blue_callout_idx != -1 and idx > blue_callout_idx:
                    if divider_idx == -1:
                        divider_idx = idx
        
            # Find version paragraph
            if block_type == "paragraph":
                if divider_idx != -1 and idx > divider_idx:
                    if "document version" in block_content.lower() and "2.0" in block_content:
                        if version_paragraph_idx == -1:
                            version_paragraph_idx = idx
    
        # 5. Validate main title exists
        if main_title_idx == -1:
            errors.append("[X] Main heading_1 'Product Requirements Document' not found")
        else:
            checks_passed.append("[C] Main heading_1 'Product Requirements Document' found")
    
        # 6. Validate Executive Summary heading exists
        if exec_summary_heading_idx == -1:
            errors.append("[X] heading_2 '📋 Executive Summary' not found")
        else:
            checks_passed.append("[C] heading_2 '📋 Executive Summary' found")
    
        # 7. Validate Executive Summary is positioned correctly (after main title, before Overview)
        if exec_summary_heading_order <= main_title_order:
            errors.append(f"[X] Executive Summary should be after main title (title at order {main_title_order}, Executive Summary at order {exec_summary_heading_order})")
        else:
            checks_passed.append(f"[C] Executive Summary should be after main title (title at order {main_title_order}, Executive Summary at order {exec_summary_heading_order})")
    
        if overview_heading_idx != -1 and exec_summary_heading_order >= overview_heading_order:
            errors.append(f"[X] Executive Summary should be before Overview (Executive Summary at order {exec_summary_heading_order}, Overview at order {overview_heading_order})")
        else:
            checks_passed.append(f"[C] Executive Summary should be before Overview (Executive Summary at order {exec_summary_heading_order}, Overview at order {overview_heading_order})")
    
        # 8. Validate blue callout exists
        if blue_callout_idx == -1:
            errors.append("[X] Blue callout with 🎯 icon not found after Executive Summary heading")
        else:
            checks_passed.append("[C] Blue callout with 🎯 icon found after Executive Summary heading")
    
        # 9. Validate callout content mentions counts
        callout_block = page_blocks[blue_callout_idx]
        callout_content = callout_block.get("content", "")
    
        if "this document outlines" not in callout_content.lower():
            errors.append(f"[X] Callout should start with 'This document outlines', found: {callout_content}")
        else:
            checks_passed.append(f"[C] Callout should start with 'This document outlines', found: {callout_content}")
    
        # Check for mention of major sections count (heading_2)
        if str(heading2_count) not in callout_content:
            errors.append(f"[X] Callout should mention {heading2_count} major sections (heading_2 blocks), content: {callout_content}")
        else:
            checks_passed.append(f"[C] Callout should mention {heading2_count} major sections (heading_2 blocks), content: {callout_content}")
    
        # Check for mention of requirements count (paragraphs)
        if str(paragraph_count) not in callout_content:
            errors.append(f"[X] Callout should mention {paragraph_count} total requirements (paragraph blocks), content: {callout_content}")
        else:
            checks_passed.append(f"[C] Callout should mention {paragraph_count} total requirements (paragraph blocks), content: {callout_content}")
    
        # 10. Validate divider exists
        if divider_idx == -1:
            errors.append("[X] Divider not found after callout")
        else:
            checks_passed.append("[C] Divider found after callout")
    
        # 11. Validate version paragraph exists
        if version_paragraph_idx == -1:
            errors.append("[X] Version paragraph with 'Document version: 2.0' not found")
        else:
            checks_passed.append("[C] Version paragraph with 'Document version: 2.0' found")
    
        # 12. Check for "last updated" text
        version_para_content = page_blocks[version_paragraph_idx].get("content", "")
        if "last updated" not in version_para_content.lower():
            errors.append(f"[X] Version paragraph should contain 'Last updated:', found: {version_para_content}")
        else:
            checks_passed.append(f"[C] Version paragraph should contain 'Last updated:', found: {version_para_content}")
    
        # ALL requirements met!
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: add-weekly-metrics-to-standup-v2
# Description: Add Weekly Metrics section after Blockers with divider, metrics, callout, and update completed todos
# =============================================================================
def _validate_agent_add_weekly_metrics_to_standup(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate Weekly Metrics section with:
    - Divider after Blockers section
    - heading_2 '📊 Weekly Metrics'
    - Paragraph with 'Team Velocity:' and regular text (TODO: should check for bold formatting in future)
    - Blue callout with 📈 icon and tracking text
    - All previously checked todos have ' ✓ Done' appended (TODO: should check for italic formatting in future)
    
    Returns 1.0 only if ALL requirements are met, otherwise 0.0
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Find the 'Weekly Standup Template' page
    try:
        standup_pages = _get_pages_by_filter(backend, {"title": "Weekly Standup Template"})
        if not standup_pages:
            standup_pages = _get_pages_by_filter(backend, {"title": "Weekly Standup"})
        if not standup_pages:
            errors.append("[X] Weekly Standup Template page not found")
        else:
            checks_passed.append("[C] Weekly Standup Template page found")
    
        standup_page = standup_pages[0]
        standup_id = standup_page.get("_id")
    
        # 2. Get all blocks for the page
        page_blocks = _get_blocks_by_filter(backend, {"pageId": standup_id})
    
        if len(page_blocks) < 5:
            errors.append(f"[X] Weekly Standup Template needs sufficient blocks, found {len(page_blocks)}")
        else:
            checks_passed.append(f"[C] Weekly Standup Template needs sufficient blocks, found {len(page_blocks)}")
    
        # 3. Find key sections
        blockers_heading_idx = -1
        blockers_heading_order = -1
        divider_after_blockers_idx = -1
        weekly_metrics_heading_idx = -1
        weekly_metrics_heading_order = -1
        velocity_paragraph_idx = -1
        blue_callout_idx = -1
    
        checked_todos = []
    
        # Sort blocks by order
        blocks_by_order = sorted(
            [(block.get("order", 0), idx, block) for idx, block in enumerate(page_blocks)],
            key=lambda x: x[0]
        )
    
        for order, idx, block in blocks_by_order:
            block_type = block.get("type", "")
            block_content = block.get("content", "")
            block_properties = block.get("properties", {})
        
            # Find Blockers heading
            if block_type == "heading2" and "blockers" in block_content.lower():
                blockers_heading_idx = idx
                blockers_heading_order = order
        
            # Find divider after Blockers
            if block_type == "divider":
                if blockers_heading_idx != -1 and order > blockers_heading_order:
                    if divider_after_blockers_idx == -1:
                        divider_after_blockers_idx = idx
        
            # Find Weekly Metrics heading
            if block_type == "heading2" and "📊" in block_content and "weekly metrics" in block_content.lower():
                weekly_metrics_heading_idx = idx
                weekly_metrics_heading_order = order
        
            # Find velocity paragraph
            if block_type == "paragraph":
                if weekly_metrics_heading_idx != -1 and idx > weekly_metrics_heading_idx:
                    if "team velocity" in block_content.lower():
                        if velocity_paragraph_idx == -1:
                            velocity_paragraph_idx = idx
        
            # Find blue callout
            if block_type == "callout":
                if weekly_metrics_heading_idx != -1 and idx > weekly_metrics_heading_idx:
                    bg_color = block_properties.get("backgroundColor", "") if isinstance(block_properties, dict) else ""
                    icon = block_properties.get("icon", "") if isinstance(block_properties, dict) else ""
                    if "blue" in bg_color.lower() and "📈" in str(icon):
                        if blue_callout_idx == -1:
                            blue_callout_idx = idx
        
            # Collect checked todos
            if block_type == "todo":
                is_checked = block_properties.get("checked", False) if isinstance(block_properties, dict) else False
                if is_checked:
                    checked_todos.append({
                        "idx": idx,
                        "content": block_content
                    })
    
        # 4. Validate Blockers heading exists
        if blockers_heading_idx == -1:
            errors.append("[X] Blockers heading_2 not found")
        else:
            checks_passed.append("[C] Blockers heading_2 found")
    
        # 5. Validate divider after Blockers
        if divider_after_blockers_idx == -1:
            errors.append("[X] Divider not found after Blockers section")
        else:
            checks_passed.append("[C] Divider found after Blockers section")
    
        # 6. Validate Weekly Metrics heading exists
        if weekly_metrics_heading_idx == -1:
            errors.append("[X] heading_2 '📊 Weekly Metrics' not found")
        else:
            checks_passed.append("[C] heading_2 '📊 Weekly Metrics' found")
    
        # 7. Validate Weekly Metrics is after divider
        if weekly_metrics_heading_order <= blockers_heading_order:
            errors.append(f"[X] Weekly Metrics should be after Blockers (Blockers at order {blockers_heading_order}, Weekly Metrics at order {weekly_metrics_heading_order})")
        else:
            checks_passed.append(f"[C] Weekly Metrics should be after Blockers (Blockers at order {blockers_heading_order}, Weekly Metrics at order {weekly_metrics_heading_order})")
    
        # 8. Validate velocity paragraph exists
        if velocity_paragraph_idx == -1:
            errors.append("[X] Paragraph with 'Team Velocity:' not found after Weekly Metrics heading")
        else:
            checks_passed.append("[C] Paragraph with 'Team Velocity:' found after Weekly Metrics heading")
    
        # 9. Validate velocity paragraph content
        # TODO: Re-enable bold formatting check when ready - should verify bold 'Team Velocity:' text
        velocity_para = page_blocks[velocity_paragraph_idx]
        velocity_content = velocity_para.get("content", "")
        if "team velocity:" not in velocity_content.lower():
            errors.append(f"[X] Velocity paragraph should contain 'Team Velocity:', found: {velocity_content}")
        else:
            checks_passed.append(f"[C] Velocity paragraph should contain 'Team Velocity:', found: {velocity_content}")
    
        if "sprint points" not in velocity_content.lower():
            errors.append(f"[X] Velocity paragraph should mention sprint points, found: {velocity_content}")
        else:
            checks_passed.append(f"[C] Velocity paragraph should mention sprint points, found: {velocity_content}")
    
        # 10. Validate blue callout exists
        if blue_callout_idx == -1:
            errors.append("[X] Blue callout with 📈 icon not found after Weekly Metrics heading")
        else:
            checks_passed.append("[C] Blue callout with 📈 icon found after Weekly Metrics heading")
    
        # 11. Validate callout content
        callout_block = page_blocks[blue_callout_idx]
        callout_content = callout_block.get("content", "")
    
        if "track key metrics" not in callout_content.lower():
            errors.append(f"[X] Callout should contain 'Track key metrics', found: {callout_content}")
        else:
            checks_passed.append(f"[C] Callout should contain 'Track key metrics', found: {callout_content}")
    
        if "week-over-week" not in callout_content.lower() and "week over week" not in callout_content.lower():
            errors.append(f"[X] Callout should mention 'week-over-week', found: {callout_content}")
        else:
            checks_passed.append(f"[C] Callout should mention 'week-over-week', found: {callout_content}")
    
        # 12. Validate checked todos have " ✓ Done" appended
        if len(checked_todos) > 0:
            todos_without_done = []
            for todo in checked_todos:
                if "✓ done" not in todo["content"].lower():
                    todos_without_done.append(todo["idx"])
        
            if todos_without_done:
                errors.append(f"[X] All checked todos should have ' ✓ Done' appended. Missing from todos at indices: {todos_without_done}")
            else:
                checks_passed.append(f"[C] All checked todos should have ' ✓ Done' appended. has from todos at indices: {todos_without_done}")
    
        # ALL requirements met!
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: create-project-roadmap-analytics-v2
# Description: Create a 'Project Roadmap Analytics' page as sibling to Project Roadmap,
# analyze Q1/Q2 Goals pages and create comprehensive analytics dashboard
# =============================================================================
def _validate_agent_create_project_roadmap_analytics(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate Project Roadmap Analytics page with:
    - New page at same level as Project Roadmap
    - Quarterly summary showing Q1 2024: 2/3 (66%) and Q2 2024: 0/2 (0%)
    - Key Results section listing all KRs
    - Status callout (orange with warning icon, 33% overall completion)
    - Timeline projection based on current progress
    
    Returns 1.0 only if ALL requirements are met, otherwise 0.0
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Find the Project Roadmap page
    try:
        roadmap_pages = _get_pages_by_filter(backend, {"title": "Project Roadmap"})
        if not roadmap_pages:
            errors.append("[X] Project Roadmap page not found")
        else:
            checks_passed.append("[C] Project Roadmap page found")
    
        roadmap_page = roadmap_pages[0]
        roadmap_parent_id = roadmap_page.get("parentId")
    
        # 2. Find the Project Roadmap Analytics page
        analytics_pages = _get_pages_by_filter(backend, {"title": "Project Roadmap Analytics"})
        if not analytics_pages:
            errors.append("[X] Project Roadmap Analytics page not found")
        else:
            checks_passed.append("[C] Project Roadmap Analytics page found")
    
        analytics_page = analytics_pages[0]
        analytics_id = analytics_page.get("_id")
        analytics_parent_id = analytics_page.get("parentId")
    
        # 3. Verify it's a sibling (same parent as Project Roadmap)
        if analytics_parent_id != roadmap_parent_id:
            errors.append(f"[X] Project Roadmap Analytics should be sibling of Project Roadmap (same parent), but has different parent")
        else:
            checks_passed.append(f"[C] Project Roadmap Analytics should be sibling of Project Roadmap (same parent), but has different parent")
    
        # 4. Get blocks for the analytics page
        analytics_blocks = _get_blocks_by_filter(backend, {"pageId": analytics_id})
        if len(analytics_blocks) < 5:
            errors.append(f"[X] Project Roadmap Analytics needs sufficient blocks, found {len(analytics_blocks)}")
        else:
            checks_passed.append(f"[C] Project Roadmap Analytics needs sufficient blocks, found {len(analytics_blocks)}")
    
        # 5. Validate heading1 with '📊 Roadmap Progress Analytics'
        heading1_found = False
        for block in analytics_blocks:
            if block.get("type") == "heading1":
                content = block.get("content", "")
                if "📊" in content and "roadmap progress analytics" in content.lower():
                    heading1_found = True
                    break
    
        if not heading1_found:
            errors.append("[X] heading1 '📊 Roadmap Progress Analytics' not found")
        else:
            checks_passed.append("[C] heading1 '📊 Roadmap Progress Analytics' found")
    
        # 6. Validate heading2 '🎯 Quarterly Objectives Summary'
        quarterly_summary_found = False
        for block in analytics_blocks:
            if block.get("type") == "heading2":
                content = block.get("content", "")
                if "🎯" in content and "quarterly objectives summary" in content.lower():
                    quarterly_summary_found = True
                    break
    
        if not quarterly_summary_found:
            errors.append("[X] heading2 '🎯 Quarterly Objectives Summary' not found")
        else:
            checks_passed.append("[C] heading2 '🎯 Quarterly Objectives Summary' found")
    
        # 7. Validate bulletedList showing Q1 2024: 2/3 (66%) and Q2 2024: 0/2 (0%)
        q1_found = False
        q2_found = False
    
        for block in analytics_blocks:
            if block.get("type") == "bulletedList":
                content = block.get("content", "")
                if "q1" in content.lower() and "2024" in content:
                    if "2/3" in content or "66" in content:
                        q1_found = True
                if "q2" in content.lower() and "2024" in content:
                    if "0/2" in content or "0%" in content:
                        q2_found = True
    
        if not q1_found:
            errors.append("[X] Q1 2024: 2/3 (66%) summary not found in bulletedList")
        else:
            checks_passed.append("[C] Q1 2024: 2/3 (66%) summary found in bulletedList")
        if not q2_found:
            errors.append("[X] Q2 2024: 0/2 (0%) summary not found in bulletedList")
        else:
            checks_passed.append("[C] Q2 2024: 0/2 (0%) summary found in bulletedList")
    
        # 8. Validate heading2 '📈 Key Results Tracking'
        key_results_found = False
        for block in analytics_blocks:
            if block.get("type") == "heading2":
                content = block.get("content", "")
                if "📈" in content and "key results tracking" in content.lower():
                    key_results_found = True
                    break
    
        if not key_results_found:
            errors.append("[X] heading2 '📈 Key Results Tracking' not found")
        else:
            checks_passed.append("[C] heading2 '📈 Key Results Tracking' found")
    
        # 9. Validate numberedList for Key Results
        numbered_list_found = False
        for block in analytics_blocks:
            if block.get("type") == "numberedList":
                numbered_list_found = True
                break
    
        if not numbered_list_found:
            errors.append("[X] numberedList for Key Results not found")
        else:
            checks_passed.append("[C] numberedList for Key Results found")
    
        # 10. Validate heading2 '🚦 Status Overview'
        status_overview_found = False
        for block in analytics_blocks:
            if block.get("type") == "heading2":
                content = block.get("content", "")
                if "🚦" in content and "status overview" in content.lower():
                    status_overview_found = True
                    break
    
        if not status_overview_found:
            errors.append("[X] heading2 '🚦 Status Overview' not found")
        else:
            checks_passed.append("[C] heading2 '🚦 Status Overview' found")
    
        # 11. Validate callout with orange background and warning icon showing 33%
        status_callout_found = False
        for block in analytics_blocks:
            if block.get("type") == "callout":
                properties = block.get("properties", {})
                bg_color = properties.get("backgroundColor", "") if isinstance(properties, dict) else ""
                icon = properties.get("icon", "") if isinstance(properties, dict) else ""
                content = block.get("content", "")
            
                if "orange" in bg_color.lower():
                    if "⚠️" in str(icon) or "⚠" in str(icon):
                        if "33" in content or "overall" in content.lower():
                            status_callout_found = True
                            break
    
        if not status_callout_found:
            errors.append("[X] Status callout with orange_background, warning icon, and 33% completion not found")
        else:
            checks_passed.append("[C] Status callout with orange_background, warning icon, and 33% completion found")
    
        # 12. Validate heading2 '🔮 Projected Timeline'
        timeline_found = False
        for block in analytics_blocks:
            if block.get("type") == "heading2":
                content = block.get("content", "")
                if "🔮" in content and "projected timeline" in content.lower():
                    timeline_found = True
                    break
    
        if not timeline_found:
            errors.append("[X] heading2 '🔮 Projected Timeline' not found")
        else:
            checks_passed.append("[C] heading2 '🔮 Projected Timeline' found")
    
        # 13. Validate paragraph with timeline projection
        projection_found = False
        for block in analytics_blocks:
            if block.get("type") == "paragraph":
                content = block.get("content", "")
                if "velocity" in content.lower() and ("completion" in content.lower() or "estimated" in content.lower()):
                    projection_found = True
                    break
    
        if not projection_found:
            errors.append("[X] Paragraph with timeline projection based on velocity not found")
        else:
            checks_passed.append("[C] Paragraph with timeline projection based on velocity found")
    
        # ALL requirements met!
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: add-mobile-user-stories-to-prd-v2
# Description: Insert Mobile User Stories subsection after 'User Stories - Part 2'
# heading but before its paragraph content in PRD
# =============================================================================
def _validate_agent_add_mobile_user_stories_to_prd(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate Mobile User Stories insertion with:
    - Inserted after 'User Stories - Part 2' heading but before its paragraph
    - Divider, then heading_3 '📱 Mobile User Stories'
    - Callout with blue_background and 📲 icon with exact text
    - Exactly 3 bulletedList items with specific mobile user stories
    
    Returns 1.0 only if ALL requirements are met, otherwise 0.0
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Find the PRD page
    try:
        prd_pages = _get_pages_by_filter(backend, {"title": "Comprehensive Product Requirements Document"})
        if not prd_pages:
            errors.append("[X] Comprehensive Product Requirements Document page not found")
        else:
            checks_passed.append("[C] Comprehensive Product Requirements Document page found")
    
        prd_page = prd_pages[0]
        prd_id = prd_page.get("_id")
    
        # 2. Get all blocks for the page
        page_blocks = _get_blocks_by_filter(backend, {"pageId": prd_id})
    
        if len(page_blocks) < 10:
            errors.append(f"[X] PRD needs sufficient blocks, found {len(page_blocks)}")
        else:
            checks_passed.append(f"[C] PRD needs sufficient blocks, found {len(page_blocks)}")
    
        # Sort blocks by order
        blocks_by_order = sorted(
            [(block.get("order", 0), idx, block) for idx, block in enumerate(page_blocks)],
            key=lambda x: x[0]
        )
    
        # 3. Find 'User Stories - Part 2' heading_3
        user_stories_part2_idx = -1
        user_stories_part2_order = -1
    
        for order, idx, block in blocks_by_order:
            if block.get("type") == "heading3":
                content = block.get("content", "")
                if "user stories" in content.lower() and "part 2" in content.lower():
                    user_stories_part2_idx = idx
                    user_stories_part2_order = order
                    break
    
        if user_stories_part2_idx == -1:
            errors.append("[X] 'User Stories - Part 2' heading_3 not found")
        else:
            checks_passed.append("[C] 'User Stories - Part 2' heading_3 found")
    
        # 4. Find divider after User Stories Part 2
        divider_idx = -1
        divider_order = -1
        for order, idx, block in blocks_by_order:
            if block.get("type") == "divider" and order > user_stories_part2_order:
                divider_idx = idx
                divider_order = order
                break
    
        if divider_idx == -1:
            errors.append("[X] Divider not found after 'User Stories - Part 2' heading")
        else:
            checks_passed.append("[C] Divider found after 'User Stories - Part 2' heading")
    
        # 5. Find heading_3 '📱 Mobile User Stories'
        mobile_heading_idx = -1
        mobile_heading_order = -1
        for order, idx, block in blocks_by_order:
            if block.get("type") == "heading3" and order > user_stories_part2_order:
                content = block.get("content", "")
                if "📱" in content and "mobile user stories" in content.lower():
                    mobile_heading_idx = idx
                    mobile_heading_order = order
                    break
    
        if mobile_heading_idx == -1:
            errors.append("[X] heading_3 '📱 Mobile User Stories' not found")
        else:
            checks_passed.append("[C] heading_3 '📱 Mobile User Stories' found")
    
        # 6. Validate callout with blue_background and 📲 icon
        callout_found = False
        callout_content = ""
        for order, idx, block in blocks_by_order:
            if block.get("type") == "callout" and order > mobile_heading_order:
                properties = block.get("properties", {})
                bg_color = properties.get("backgroundColor", "") if isinstance(properties, dict) else ""
                icon = properties.get("icon", "") if isinstance(properties, dict) else ""
            
                if "blue" in bg_color.lower() and "📲" in str(icon):
                    content = block.get("content", "")
                    if "mobile-first" in content.lower() and "critical" in content.lower():
                        callout_found = True
                        callout_content = content
                        break
    
        if not callout_found:
            errors.append("[X] Callout with blue_background, 📲 icon, and exact text not found")
        else:
            checks_passed.append("[C] Callout with blue_background, 📲 icon, and exact text found")
    
        # 7. Validate exactly 3 bulletedList items with specific user stories
        mobile_user_stories = []
        for order, idx, block in blocks_by_order:
            if block.get("type") == "bulletedList" and order > mobile_heading_order:
                content = block.get("content", "")
                if "as a mobile user" in content.lower():
                    mobile_user_stories.append(content)
    
        if len(mobile_user_stories) < 3:
            errors.append(f"[X] Expected 3 mobile user stories bulletedList items, found {len(mobile_user_stories)}")
        else:
            checks_passed.append(f"[C] Found 3 mobile user stories bulletedList items as expected")
    
        # Check for specific stories
        offline_found = any("offline" in story.lower() for story in mobile_user_stories)
        push_notif_found = any("push notification" in story.lower() for story in mobile_user_stories)
        biometric_found = any("biometric" in story.lower() for story in mobile_user_stories)
    
        if not offline_found:
            errors.append("[X] Mobile user story about offline access not found")
        else:
            checks_passed.append("[C] Mobile user story about offline access found")
        if not push_notif_found:
            errors.append("[X] Mobile user story about push notifications not found")
        else:
            checks_passed.append("[C] Mobile user story about push notifications found")
        if not biometric_found:
            errors.append("[X] Mobile user story about biometric authentication not found")
        else:
            checks_passed.append("[C] Mobile user story about biometric authentication found")
    
        # ALL requirements met!
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: create-code-review-standards-v2
# Description: Create Code Review Standards page under Engineering Wiki,
# fetch and organize callouts by color from Project Guidelines page
# =============================================================================
def _validate_agent_create_code_review_standards(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate Code Review Standards page with:
    - Page exists under Engineering Wiki
    - heading_1 '🔍 Code Review Standards'
    - Callouts grouped by background color with section headings
    - All callout content/icons/colors match source page exactly
    - Review checklist with 5 specific unchecked todos after divider
    
    Returns 1.0 only if ALL requirements are met, otherwise 0.0
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Find Engineering Wiki page
    try:
        wiki_pages = _get_pages_by_filter(backend, {"title": "Engineering Wiki"})
        if not wiki_pages:
            errors.append("[X] Engineering Wiki page not found")
        else:
            checks_passed.append("[C] Engineering Wiki page found")
    
        wiki_page = wiki_pages[0]
        wiki_id = wiki_page.get("_id")
    
        # 2. Find Code Review Standards page as child of Engineering Wiki
        child_pages = _get_pages_by_filter(backend, {"parentId": wiki_id})
        standards_page = None
        for p in child_pages:
            if "code review standards" in p.get("title", "").lower():
                standards_page = p
                break
        if not standards_page:
            errors.append("[X] Code Review Standards page not found under Engineering Wiki")
        else:
            checks_passed.append("[C] Code Review Standards page found under Engineering Wiki")
    
        standards_id = standards_page.get("_id")
    
        # 3. Get blocks for the standards page
        standards_blocks = _get_blocks_by_filter(backend, {"pageId": standards_id})
    
        if len(standards_blocks) < 5:
            errors.append(f"[X] Code Review Standards needs sufficient blocks, found {len(standards_blocks)}")
        else:
            checks_passed.append(f"[C] Code Review Standards needs sufficient blocks, found {len(standards_blocks)}")
    
        # 4. Validate heading_1 '🔍 Code Review Standards'
        heading1_found = False
        for block in standards_blocks:
            if block.get("type") == "heading1":
                content = block.get("content", "")
                if "🔍" in content and "code review standards" in content.lower():
                    heading1_found = True
                    break
    
        if not heading1_found:
            errors.append("[X] heading_1 '🔍 Code Review Standards' not found")
        else:
            checks_passed.append("[C] heading_1 '🔍 Code Review Standards' found")
    
        # 5. Check for color-based section headings (e.g., 'Yellow Level Guidelines')
        color_sections = []
        for block in standards_blocks:
            if block.get("type") == "heading2":
                content = block.get("content", "")
                if "level guidelines" in content.lower():
                    color_sections.append(content)
    
        if len(color_sections) < 1:
            errors.append("[X] No color-based section headings found (e.g., 'Yellow Level Guidelines')")
        else:
            checks_passed.append("[C] color-based section headings found (e.g., 'Yellow Level Guidelines')")
    
        # 6. Validate callouts exist with different background colors
        callout_colors = set()
        for block in standards_blocks:
            if block.get("type") == "callout":
                properties = block.get("properties", {})
                bg_color = properties.get("backgroundColor", "") if isinstance(properties, dict) else ""
                if bg_color:
                    callout_colors.add(bg_color)
    
        if len(callout_colors) < 1:
            errors.append("[X] No callout blocks found with background colors")
        else:
            checks_passed.append("[C] callout blocks found with background colors")
    
        # 7. Validate divider exists
        divider_found = False
        for block in standards_blocks:
            if block.get("type") == "divider":
                divider_found = True
                break
    
        if not divider_found:
            errors.append("[X] Divider not found before review checklist")
        else:
            checks_passed.append("[C] Divider found before review checklist")
    
        # 8. Validate heading_2 '📋 Review Checklist'
        checklist_found = False
        for block in standards_blocks:
            if block.get("type") == "heading2":
                content = block.get("content", "")
                if "📋" in content and "review checklist" in content.lower():
                    checklist_found = True
                    break
    
        if not checklist_found:
            errors.append("[X] heading_2 '📋 Review Checklist' not found")
        else:
            checks_passed.append("[C] heading_2 '📋 Review Checklist' found")
    
        # 9. Validate 5 specific unchecked todo blocks
        todos = []
        for block in standards_blocks:
            if block.get("type") == "todo":
                content = block.get("content", "")
                properties = block.get("properties", {})
                is_checked = properties.get("checked", False) if isinstance(properties, dict) else False
                todos.append({"content": content, "checked": is_checked})
    
        if len(todos) < 5:
            errors.append(f"[X] Expected 5 todo items in checklist, found {len(todos)}")
        else:
            checks_passed.append(f"[C] Found 5 todo items in checklist as expected")
    
        # Check for specific todos
        required_todos = [
            "style guidelines",
            "tests",
            "documentation",
            "security",
            "performance"
        ]
    
        for required in required_todos:
            found = any(required in todo["content"].lower() for todo in todos)
            if not found:
                errors.append(f"[X] Required todo item about '{required}' not found")
            else:
                checks_passed.append(f"[C] Required todo item about '{required}' found")
    
        # Check that todos are unchecked
        checked_todos = [todo for todo in todos if todo["checked"]]
        if checked_todos:
            errors.append(f"[X] Todo items should be unchecked, found {len(checked_todos)} checked")
        else:
            checks_passed.append(f"[C] Todo items should be unchecked, found {len(checked_todos)} checked")
    
        # ALL requirements met!
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: create-development-workflow-guide-v2
# Description: Create Development Workflow Guide under Engineering Wiki,
# extract callouts by color from Project Guidelines and add workflow steps
# =============================================================================
def _validate_agent_create_development_workflow_guide(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate Development Workflow Guide with:
    - Page exists under Engineering Wiki
    - heading_1 '🔧 Development Workflow Guide'
    - heading_2 '⚡ Quick Tips' with yellow callouts
    - heading_2 '🚨 Critical Warnings' with red callouts
    - heading_2 '📋 Standard Workflow' with 7 numbered steps
    - Divider and paragraph at end (TODO: should check for italic formatting in future)
    
    Returns 1.0 only if ALL requirements are met, otherwise 0.0
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Find Engineering Wiki page
    try:
        wiki_pages = _get_pages_by_filter(backend, {"title": "Engineering Wiki"})
        if not wiki_pages:
            errors.append("[X] Engineering Wiki page not found")
        else:
            checks_passed.append("[C] Engineering Wiki page found")
        wiki_page = wiki_pages[0]
    
        # 2. Find Development Workflow Guide page under Engineering Wiki
        workflow_pages = _get_pages_by_filter(backend, {"parentId": wiki_page.get("_id")})
        workflow_page = next((p for p in workflow_pages if "development workflow guide" in p.get("title", "").lower()), None)
        if not workflow_page:
            errors.append("[X] Development Workflow Guide page not found under Engineering Wiki")
        else:
            checks_passed.append("[C] Development Workflow Guide page found under Engineering Wiki")
    
        workflow_id = workflow_page.get("_id")
    
        # 3. Get blocks for the workflow page
        workflow_blocks = _get_blocks_by_filter(backend, {"pageId": workflow_id})
    
        if len(workflow_blocks) < 10:
            errors.append(f"[X] Development Workflow Guide needs sufficient blocks, found {len(workflow_blocks)}")
        else:
            checks_passed.append(f"[C] Development Workflow Guide needs sufficient blocks, found {len(workflow_blocks)}")
    
        # 4. Validate heading_1 '🔧 Development Workflow Guide'
        heading1_found = False
        for block in workflow_blocks:
            if block.get("type") == "heading1":
                content = block.get("content", "")
                if "🔧" in content and "development workflow guide" in content.lower():
                    heading1_found = True
                    break
    
        if not heading1_found:
            errors.append("[X] heading_1 '🔧 Development Workflow Guide' not found")
        else:
            checks_passed.append("[C] heading_1 '🔧 Development Workflow Guide' found")
    
        # 5. Validate heading_2 '⚡ Quick Tips'
        quick_tips_found = False
        for block in workflow_blocks:
            if block.get("type") == "heading2":
                content = block.get("content", "")
                if "⚡" in content and "quick tips" in content.lower():
                    quick_tips_found = True
                    break
    
        if not quick_tips_found:
            errors.append("[X] heading_2 '⚡ Quick Tips' not found")
        else:
            checks_passed.append("[C] heading_2 '⚡ Quick Tips' found")
    
        # 6. Validate yellow callouts exist
        yellow_callouts = []
        for block in workflow_blocks:
            if block.get("type") == "callout":
                properties = block.get("properties", {})
                bg_color = properties.get("backgroundColor", "") if isinstance(properties, dict) else ""
                if "yellow" in bg_color.lower():
                    yellow_callouts.append(block)
    
        if len(yellow_callouts) < 1:
            errors.append("[X] No yellow callouts found under Quick Tips section")
        else:
            checks_passed.append("[C] yellow callouts found under Quick Tips section")
    
        # 7. Validate heading_2 '🚨 Critical Warnings'
        warnings_found = False
        for block in workflow_blocks:
            if block.get("type") == "heading2":
                content = block.get("content", "")
                if "🚨" in content and "critical warnings" in content.lower():
                    warnings_found = True
                    break
    
        if not warnings_found:
            errors.append("[X] heading_2 '🚨 Critical Warnings' not found")
        else:
            checks_passed.append("[C] heading_2 '🚨 Critical Warnings' found")
    
        # 8. Validate red callouts exist
        red_callouts = []
        for block in workflow_blocks:
            if block.get("type") == "callout":
                properties = block.get("properties", {})
                bg_color = properties.get("backgroundColor", "") if isinstance(properties, dict) else ""
                if "red" in bg_color.lower():
                    red_callouts.append(block)
    
        if len(red_callouts) < 1:
            errors.append("[X] No red callouts found under Critical Warnings section")
        else:
            checks_passed.append("[C] red callouts found under Critical Warnings section")
    
        # 9. Validate heading_2 '📋 Standard Workflow'
        workflow_heading_found = False
        for block in workflow_blocks:
            if block.get("type") == "heading2":
                content = block.get("content", "")
                if "📋" in content and "standard workflow" in content.lower():
                    workflow_heading_found = True
                    break
    
        if not workflow_heading_found:
            errors.append("[X] heading_2 '📋 Standard Workflow' not found")
        else:
            checks_passed.append("[C] heading_2 '📋 Standard Workflow' found")
    
        # 10. Validate 7 numbered steps
        numbered_steps = []
        for block in workflow_blocks:
            if block.get("type") == "numberedList":
                content = block.get("content", "")
                numbered_steps.append(content)
    
        if len(numbered_steps) < 7:
            errors.append(f"[X] Expected 7 numbered workflow steps, found {len(numbered_steps)}")
        else:
            checks_passed.append(f"[C] Found 7 numbered workflow steps as expected")
    
        # Check for specific steps
        required_steps = [
            "feature branch",
            "write tests",
            "implement",
            "linting",
            "pull request",
            "code review",
            "merge"
        ]
    
        for required in required_steps:
            found = any(required in step.lower() for step in numbered_steps)
            if not found:
                errors.append(f"[X] Required workflow step about '{required}' not found")
            else:
                checks_passed.append(f"[C] Required workflow step about '{required}' found")
    
        # 11. Validate divider exists
        divider_found = False
        for block in workflow_blocks:
            if block.get("type") == "divider":
                divider_found = True
                break
    
        if not divider_found:
            errors.append("[X] Divider not found before final paragraph")
        else:
            checks_passed.append("[C] Divider found before final paragraph")
    
        # 12. Validate paragraph about best practices at end
        # TODO: Re-enable italic formatting check when ready - should verify italic formatting
        best_practices_paragraph_found = False
        for block in workflow_blocks:
            if block.get("type") == "paragraph":
                content = block.get("content", "")
                if "aggregates best practices" in content.lower() or "best practices" in content.lower():
                    best_practices_paragraph_found = True
                    break
    
        if not best_practices_paragraph_found:
            errors.append("[X] Paragraph about aggregating best practices not found")
        else:
            checks_passed.append("[C] Paragraph about aggregating best practices found")
    
        # ALL requirements met!
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: create-quarterly-roadmap-tracker-v2
# Description: Create Quarterly Roadmap Tracker as child of Project Roadmap,
# analyze Q1/Q2 pages and provide statistics
# =============================================================================
def _validate_agent_create_quarterly_roadmap_tracker(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate Quarterly Roadmap Tracker with:
    - Page created under Project Roadmap
    - heading_1 '🗓️ Quarterly Roadmap Tracker'
    - heading_2 '📊 Quarter Overview'
    - For each quarter: heading_3 and blue callout with stats
    - heading_2 '🎯 Cross-Quarter Insights' with calculations
    
    Returns 1.0 only if ALL requirements are met, otherwise 0.0
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Find Project Roadmap page
    try:
        roadmap_pages = _get_pages_by_filter(backend, {"title": "Project Roadmap"})
        if not roadmap_pages:
            errors.append("[X] Project Roadmap page not found")
        else:
            checks_passed.append("[C] Project Roadmap page found")
        roadmap_page = roadmap_pages[0]
    
        # 2. Find Quarterly Roadmap Tracker as child
        child_pages = _get_pages_by_filter(backend, {"parentId": roadmap_page.get("_id")})
        tracker_page = next((p for p in child_pages if "quarterly roadmap tracker" in p.get("title", "").lower()), None)
        if not tracker_page:
            errors.append("[X] Quarterly Roadmap Tracker page not found under Project Roadmap")
        else:
            checks_passed.append("[C] Quarterly Roadmap Tracker page found under Project Roadmap")
    
        tracker_id = tracker_page.get("_id")
    
        # 3. Get blocks for the tracker page
        tracker_blocks = _get_blocks_by_filter(backend, {"pageId": tracker_id})
    
        if len(tracker_blocks) < 5:
            errors.append(f"[X] Quarterly Roadmap Tracker needs sufficient blocks, found {len(tracker_blocks)}")
        else:
            checks_passed.append(f"[C] Quarterly Roadmap Tracker needs sufficient blocks, found {len(tracker_blocks)}")
    
        # 4. Validate heading_1 '🗓️ Quarterly Roadmap Tracker'
        heading1_found = False
        for block in tracker_blocks:
            if block.get("type") == "heading1":
                content = block.get("content", "")
                if "🗓️" in content and "quarterly roadmap tracker" in content.lower():
                    heading1_found = True
                    break
    
        if not heading1_found:
            errors.append("[X] heading_1 '🗓️ Quarterly Roadmap Tracker' not found")
        else:
            checks_passed.append("[C] heading_1 '🗓️ Quarterly Roadmap Tracker' found")
    
        # 5. Validate heading_2 '📊 Quarter Overview'
        overview_found = False
        for block in tracker_blocks:
            if block.get("type") == "heading2":
                content = block.get("content", "")
                if "📊" in content and "quarter overview" in content.lower():
                    overview_found = True
                    break
    
        if not overview_found:
            errors.append("[X] heading_2 '📊 Quarter Overview' not found")
        else:
            checks_passed.append("[C] heading_2 '📊 Quarter Overview' found")
    
        # 6. Validate quarter heading_3 blocks (should have Q1 or Q2)
        quarter_headings = []
        for block in tracker_blocks:
            if block.get("type") == "heading3":
                content = block.get("content", "")
                if "q1" in content.lower() or "q2" in content.lower():
                    quarter_headings.append(content)
    
        if len(quarter_headings) < 1:
            errors.append("[X] No quarter heading_3 blocks found (e.g., Q1 2024, Q2 2024)")
        else:
            checks_passed.append("[C] quarter heading_3 blocks found (e.g., Q1 2024, Q2 2024)")
    
        # 7. Validate blue callouts with statistics
        blue_callouts = []
        for block in tracker_blocks:
            if block.get("type") == "callout":
                properties = block.get("properties", {})
                bg_color = properties.get("backgroundColor", "") if isinstance(properties, dict) else ""
                if "blue" in bg_color.lower():
                    content = block.get("content", "")
                    if "sections:" in content.lower() or "tasks:" in content.lower():
                        blue_callouts.append(content)
    
        if len(blue_callouts) < 1:
            errors.append("[X] No blue callouts with quarter statistics found")
        else:
            checks_passed.append("[C] blue callouts with quarter statistics found")
    
        # 8. Validate heading_2 '🎯 Cross-Quarter Insights'
        insights_found = False
        for block in tracker_blocks:
            if block.get("type") == "heading2":
                content = block.get("content", "")
                if "🎯" in content and "cross-quarter insights" in content.lower():
                    insights_found = True
                    break
    
        if not insights_found:
            errors.append("[X] heading_2 '🎯 Cross-Quarter Insights' not found")
        else:
            checks_passed.append("[C] heading_2 '🎯 Cross-Quarter Insights' found")
    
        # 9. Validate paragraph with calculations
        calculation_found = False
        for block in tracker_blocks:
            if block.get("type") == "paragraph":
                content = block.get("content", "")
                if "average" in content.lower() and "completion rate" in content.lower():
                    calculation_found = True
                    break
    
        if not calculation_found:
            errors.append("[X] Paragraph with average tasks and completion rate calculations not found")
        else:
            checks_passed.append("[C] Paragraph with average tasks and completion rate calculations found")
    
        # ALL requirements met!
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: add-priority-callouts-to-user-stories-v2
# Description: Add priority callouts and acceptance criteria to all
# 'Part' subsections in User Stories section of PRD
# =============================================================================
def _validate_agent_add_priority_callouts_to_user_stories(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate priority callouts and acceptance criteria with:
    - Orange callout with 📌 icon before each 'Part' heading_3
    - Divider after each Part subsection's last bulletedList
    - 'Acceptance Criteria:' paragraph followed by 2 numbered items (TODO: should check for bold formatting in future)
    - Quote block at end showing total count of updated sections
    
    Returns 1.0 only if ALL requirements are met, otherwise 0.0
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Find the PRD page
    try:
        prd_pages = _get_pages_by_filter(backend, {"title": "Comprehensive Product Requirements Document"})
        if not prd_pages:
            errors.append("[X] Comprehensive Product Requirements Document page not found")
        else:
            checks_passed.append("[C] Comprehensive Product Requirements Document page found")
        prd_page = prd_pages[0]
    
        prd_id = prd_page.get("_id")
    
        # 2. Get all blocks for the page
        page_blocks = _get_blocks_by_filter(backend, {"pageId": prd_id})
    
        if len(page_blocks) < 10:
            errors.append(f"[X] PRD needs sufficient blocks, found {len(page_blocks)}")
        else:
            checks_passed.append(f"[C] PRD needs sufficient blocks, found {len(page_blocks)}")
    
        # Sort blocks by order
        blocks_by_order = sorted(
            [(block.get("order", 0), idx, block) for idx, block in enumerate(page_blocks)],
            key=lambda x: x[0]
        )

        # 3. Find the User Stories section boundaries
        user_stories_start = None
        user_stories_end = None

        for order, idx, block in blocks_by_order:
            if block.get("type") == "heading2":
                content = block.get("content", "")
                if "user stories" in content.lower() and user_stories_start is None:
                    user_stories_start = order
                elif user_stories_start is not None and user_stories_end is None:
                    # Found the next heading_2 after User Stories
                    user_stories_end = order
                    break

        if user_stories_start is None:
            errors.append("[X] User Stories heading_2 section not found")
        else:
            checks_passed.append("[C] User Stories heading_2 section found")

        # If no next heading_2, set end to a large number (end of document)
        if user_stories_end is None:
            user_stories_end = float('inf')

        # 4. Find all heading_3 blocks containing 'Part' ONLY within User Stories section
        part_headings = []
        for order, idx, block in blocks_by_order:
            if block.get("type") == "heading3":
                content = block.get("content", "")
                if "part" in content.lower():
                    # Only include if within User Stories section bounds
                    if user_stories_start < order < user_stories_end:
                        part_headings.append({"order": order, "idx": idx, "content": content})

        if len(part_headings) < 1:
            errors.append("[X] No heading_3 blocks containing 'Part' found in User Stories section")
        else:
            checks_passed.append("[C] heading_3 blocks containing 'Part' found in User Stories section")
    
        # 5. For each Part heading, validate orange callout IMMEDIATELY BEFORE it
        orange_callouts_found = 0
        for part in part_headings:
            # Look for orange callout immediately before this part heading
            # Find the block immediately before this Part heading
            prev_block = None
            for order, idx, block in blocks_by_order:
                if order >= part["order"]:
                    break
                prev_block = block

            if prev_block and prev_block.get("type") == "callout":
                properties = prev_block.get("properties", {})
                bg_color = properties.get("backgroundColor", "") if isinstance(properties, dict) else ""
                icon = properties.get("icon", "") if isinstance(properties, dict) else ""

                if "orange" in bg_color.lower() and "📌" in str(icon):
                    content = prev_block.get("content", "")
                    if "section priority" in content.lower() and "high" in content.lower():
                        orange_callouts_found += 1

        if orange_callouts_found < len(part_headings):
            errors.append(f"[X] Expected {len(part_headings)} orange priority callouts (one immediately before each Part heading in User Stories), found {orange_callouts_found}")
        else:
            checks_passed.append(f"[C] Expected {len(part_headings)} orange priority callouts (one immediately before each Part heading in User Stories), found {orange_callouts_found}")
    
        # 6. Validate dividers exist in User Stories section (after Part subsections)
        dividers_found = 0
        for order, idx, block in blocks_by_order:
            if block.get("type") == "divider":
                # Only count dividers within User Stories section
                if user_stories_start < order < user_stories_end:
                    dividers_found += 1

        if dividers_found < len(part_headings):
            errors.append(f"[X] Expected at least {len(part_headings)} dividers (one after each Part subsection in User Stories), found {dividers_found}")
        else:
            checks_passed.append(f"[C] Expected at least {len(part_headings)} dividers (one after each Part subsection in User Stories), found {dividers_found}")

        # 7. Validate 'Acceptance Criteria:' paragraphs in User Stories section
        acceptance_criteria_found = 0
        for order, idx, block in blocks_by_order:
            if block.get("type") == "paragraph":
                content = block.get("content", "")
                if "acceptance criteria" in content.lower():
                    # Only count within User Stories section
                    if user_stories_start < order < user_stories_end:
                        acceptance_criteria_found += 1

        if acceptance_criteria_found < len(part_headings):
            errors.append(f"[X] Expected {len(part_headings)} 'Acceptance Criteria:' paragraphs in User Stories, found {acceptance_criteria_found}")
        else:
            checks_passed.append(f"[C] Expected {len(part_headings)} 'Acceptance Criteria:' paragraphs in User Stories, found {acceptance_criteria_found}")

        # 8. Validate numbered lists with 2 items per Part in User Stories section
        numbered_lists = []
        for order, idx, block in blocks_by_order:
            if block.get("type") == "numberedList":
                content = block.get("content", "")
                if "implementation" in content.lower() or "unit tests" in content.lower() or "80%" in content.lower():
                    # Only count within User Stories section
                    if user_stories_start < order < user_stories_end:
                        numbered_lists.append(content)

        if len(numbered_lists) < len(part_headings) * 2:
            errors.append(f"[X] Expected at least {len(part_headings) * 2} numbered list items (2 per Part in User Stories), found {len(numbered_lists)}")
        else:
            checks_passed.append(f"[C] Expected at least {len(part_headings) * 2} numbered list items (2 per Part in User Stories), found {len(numbered_lists)}")

        # 9. Validate quote block with total count at end of User Stories section
        quote_found = False
        for order, idx, block in blocks_by_order:
            if block.get("type") == "quote":
                content = block.get("content", "")
                if "total" in content.lower() and "sections updated" in content.lower():
                    # Should be within User Stories section
                    if user_stories_start < order < user_stories_end:
                        quote_found = True
                        break

        if not quote_found:
            errors.append("[X] Quote block showing total sections updated not found in User Stories section")
        else:
            checks_passed.append("[C] Quote block showing total sections updated found in User Stories section")
    
        # ALL requirements met!
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: add-sprint-commitment-and-metrics-task-v2
# Description: Add Carol's metrics task and sprint commitment callout
# to Sprint Planning Jan 15 page
# =============================================================================
def _validate_agent_add_sprint_commitment_and_metrics_task(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate sprint commitment callout and metrics task with:
    - Yellow callout with 📌 icon at beginning of Action Items
    - New unchecked todo '📊 Carol: Create metrics dashboard...' as 3rd item
    - Callout has exact text about sprint commitment
    
    Returns 1.0 only if ALL requirements are met, otherwise 0.0
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Find Sprint Planning page
    try:
        sprint_pages = _get_pages_by_filter(backend, {"title": "Sprint Planning - Jan 15"})
        if not sprint_pages:
            sprint_pages = _get_pages_by_filter(backend, {"title": "Sprint Planning"})
        if not sprint_pages:
            errors.append("[X] Sprint Planning - Jan 15 page not found")
        else:
            checks_passed.append("[C] Sprint Planning - Jan 15 page found")
        sprint_page = sprint_pages[0]
    
        sprint_id = sprint_page.get("_id")
    
        # 2. Get all blocks for the page
        page_blocks = _get_blocks_by_filter(backend, {"pageId": sprint_id})
    
        if len(page_blocks) < 5:
            errors.append(f"[X] Sprint Planning page needs sufficient blocks, found {len(page_blocks)}")
        else:
            checks_passed.append(f"[C] Sprint Planning page needs sufficient blocks, found {len(page_blocks)}")
    
        # Sort blocks by order
        blocks_by_order = sorted(
            [(block.get("order", 0), idx, block) for idx, block in enumerate(page_blocks)],
            key=lambda x: x[0]
        )
    
        # 3. Find Action Items heading
        action_items_idx = -1
        action_items_order = -1
        for order, idx, block in blocks_by_order:
            if block.get("type") == "heading2":
                content = block.get("content", "")
                if "action items" in content.lower():
                    action_items_idx = idx
                    action_items_order = order
                    break
    
        if action_items_idx == -1:
            errors.append("[X] 'Action Items' heading_2 not found")
        else:
            checks_passed.append("[C] 'Action Items' heading_2 found")
    
        # 4. Validate yellow callout with 📌 icon after Action Items heading
        callout_found = False
        for order, idx, block in blocks_by_order:
            if block.get("type") == "callout" and order > action_items_order:
                properties = block.get("properties", {})
                bg_color = properties.get("backgroundColor", "") if isinstance(properties, dict) else ""
                icon = properties.get("icon", "") if isinstance(properties, dict) else ""
            
                if "yellow" in bg_color.lower() and "📌" in str(icon):
                    content = block.get("content", "")
                    if "sprint commitment" in content.lower() and "january 29" in content.lower():
                        callout_found = True
                        break
    
        if not callout_found:
            errors.append("[X] Yellow callout with 📌 icon and sprint commitment text not found after Action Items heading")
        else:
            checks_passed.append("[C] Yellow callout with 📌 icon and sprint commitment text found after Action Items heading")
    
        # 5. Find all todos in Action Items section
        todos = []
        for order, idx, block in blocks_by_order:
            if block.get("type") == "todo" and order > action_items_order:
                content = block.get("content", "")
                properties = block.get("properties", {})
                is_checked = properties.get("checked", False) if isinstance(properties, dict) else False
                todos.append({
                    "order": order,
                    "idx": idx,
                    "content": content,
                    "checked": is_checked
                })
    
        if len(todos) < 3:
            errors.append(f"[X] Expected at least 3 todos in Action Items section, found {len(todos)}")
        else:
            checks_passed.append(f"[C] Found at least 3 todos in Action Items section ({len(todos)})")
    
        # 6. Validate Carol's metrics task is the 3rd todo
        third_todo = todos[2] if len(todos) >= 3 else None
        if not third_todo:
            errors.append("[X] Third todo not found in Action Items section")
        else:
            checks_passed.append("[C] Third todo found in Action Items section")
    
        carol_task_content = third_todo["content"]
        if "📊" not in carol_task_content or "carol" not in carol_task_content.lower():
            errors.append(f"[X] Third todo should be Carol's metrics task with 📊 emoji, found: {carol_task_content}")
        else:
            checks_passed.append(f"[C] Third todo should be Carol's metrics task with 📊 emoji, found: {carol_task_content}")
    
        if "metrics dashboard" not in carol_task_content.lower() or "velocity" not in carol_task_content.lower():
            errors.append(f"[X] Third todo should mention 'metrics dashboard' and 'velocity', found: {carol_task_content}")
        else:
            checks_passed.append(f"[C] Third todo should mention 'metrics dashboard' and 'velocity', found: {carol_task_content}")
    
        if third_todo["checked"]:
            errors.append("[X] Carol's metrics task should be unchecked")
        else:
            checks_passed.append("[C] Carol's metrics task should be unchecked")
    
        # ALL requirements met!
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: create-component-library-audit-v2
# Description: Create Component Library Audit page under Component Library
# with statistics and recent updates
# =============================================================================
def _validate_agent_create_component_library_audit(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate Component Library Audit with:
    - Page exists under Component Library
    - heading_1 '🧩 Component Library Audit Report'
    - heading_2 '📊 Library Statistics' with today's date
    - Yellow callout with 📋 icon containing NESTED bulletedList children:
      - The 4 bulletedList blocks must be children of the callout block (nested)
      - NOT separate page-level blocks following the callout
      - Must contain: 'Total components documented: 24', 'Components with examples: 18',
        'Components needing updates: 6', 'Last major revision: 2 weeks ago'
    - heading_2 '🔄 Recent Updates' with 3 unchecked todos
    
    Returns 1.0 only if ALL requirements are met, otherwise 0.0
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    # 1. Find Component Library page
    try:
        library_page = _find_page_by_title(final_state_backend, "Component Library")
        if not library_page:
            errors.append("[X] Component Library page not found")
        else:
            checks_passed.append("[C] Component Library page found")
    
        # 2. Find Component Library Audit as child
        audit_page = _find_child_by_title(final_state_backend, library_page, "Component Library Audit")
        if not audit_page:
            errors.append("[X] Component Library Audit page not found under Component Library")
        else:
            checks_passed.append("[C] Component Library Audit page found under Component Library")
    
        audit_id = audit_page.get("_id")
    
        # 3. Get blocks for the audit page
        audit_blocks = _get_blocks_for_page(final_state_backend, audit_id)
    
        if len(audit_blocks) < 5:
            errors.append(f"[X] Component Library Audit needs sufficient blocks, found {len(audit_blocks)}")
        else:
            checks_passed.append(f"[C] Component Library Audit needs sufficient blocks, found {len(audit_blocks)}")
    
        # 4. Validate heading_1 '🧩 Component Library Audit Report'
        heading1_found = False
        for block in audit_blocks:
            if block.get("type") == "heading1":
                content = block.get("content", "")
                if "🧩" in content and "component library audit" in content.lower():
                    heading1_found = True
                    break
    
        if not heading1_found:
            errors.append("[X] heading_1 '🧩 Component Library Audit Report' not found")
        else:
            checks_passed.append("[C] heading_1 '🧩 Component Library Audit Report' found")
    
        # 5. Validate heading_2 '📊 Library Statistics'
        statistics_found = False
        for block in audit_blocks:
            if block.get("type") == "heading2":
                content = block.get("content", "")
                if "📊" in content and "library statistics" in content.lower():
                    statistics_found = True
                    break
    
        if not statistics_found:
            errors.append("[X] heading_2 '📊 Library Statistics' not found")
        else:
            checks_passed.append("[C] heading_2 '📊 Library Statistics' found")
    
        # 6. Validate paragraph with today's date
        date_found = False
        for block in audit_blocks:
            if block.get("type") == "paragraph":
                content = block.get("content", "")
                if "audit conducted" in content.lower():
                    date_found = True
                    break
    
        if not date_found:
            errors.append("[X] Paragraph with 'Audit conducted on [date]' not found")
        else:
            checks_passed.append("[C] Paragraph with 'Audit conducted on [date]' found")
    
        # 7. Validate yellow callout with 📋 icon containing NESTED bulletedList children
        yellow_callout_found = False
        callout_children_bullets = []
    
        for block in audit_blocks:
            if block.get("type") == "callout":
                properties = block.get("properties", {})
                bg_color = properties.get("backgroundColor", "") if isinstance(properties, dict) else ""
                icon = properties.get("icon", "") if isinstance(properties, dict) else ""
            
                if "yellow" in bg_color.lower() and "📋" in str(icon):
                    yellow_callout_found = True
                
                    # Check for nested children blocks inside the callout
                    children = block.get("children", [])
                    if isinstance(children, list):
                        for child in children:
                            if isinstance(child, dict) and child.get("type") == "bulletedList":
                                child_content = child.get("content", "")
                                callout_children_bullets.append(child_content)
                    break
    
        if not yellow_callout_found:
            errors.append("[X] Yellow callout with 📋 icon not found")
        else:
            checks_passed.append("[C] Yellow callout with 📋 icon found")
    
        # 8. Validate that the callout has nested bulletedList children with statistics
        # The bulletedList items should be INSIDE the callout as children, not as separate page-level blocks
        if len(callout_children_bullets) < 4:
            errors.append(f"[X] Yellow callout must have nested bulletedList children with statistics (expected 4, found {len(callout_children_bullets)}). The bulleted items should be children of the callout block, not separate page-level blocks.")
        else:
            checks_passed.append(f"[C] Yellow callout must have nested bulletedList children with statistics (Found 4 as expected")
    
        # Validate the statistics content in nested bullets
        has_total_components = any("total components" in bullet.lower() for bullet in callout_children_bullets)
        has_with_examples = any("components with examples" in bullet.lower() for bullet in callout_children_bullets)
        has_needing_updates = any("needing updates" in bullet.lower() for bullet in callout_children_bullets)
        has_last_revision = any("last" in bullet.lower() and "revision" in bullet.lower() for bullet in callout_children_bullets)
    
        if not has_total_components:
            errors.append("[X] Nested bullet in callout missing: 'Total components documented: 24'")
        else:
            checks_passed.append("[C] Nested bullet in callout has: 'Total components documented: 24'")
        if not has_with_examples:
            errors.append("[X] Nested bullet in callout missing: 'Components with examples: 18'")
        else:
            checks_passed.append("[C] Nested bullet in callout has: 'Components with examples: 18'")
        if not has_needing_updates:
            errors.append("[X] Nested bullet in callout missing: 'Components needing updates: 6'")
        else:
            checks_passed.append("[C] Nested bullet in callout has: 'Components needing updates: 6'")
        if not has_last_revision:
            errors.append("[X] Nested bullet in callout missing: 'Last major revision: 2 weeks ago'")
        else:
            checks_passed.append("[C] Nested bullet in callout has: 'Last major revision: 2 weeks ago'")
    
        statistics_bullets = callout_children_bullets  # For the success message
    
        # 9. Validate heading_2 '🔄 Recent Updates'
        updates_found = False
        for block in audit_blocks:
            if block.get("type") == "heading2":
                content = block.get("content", "")
                if "🔄" in content and "recent updates" in content.lower():
                    updates_found = True
                    break
    
        if not updates_found:
            errors.append("[X] heading_2 '🔄 Recent Updates' not found")
        else:
            checks_passed.append("[C] heading_2 '🔄 Recent Updates' found")
    
        # 10. Validate 3 unchecked todos
        todos = []
        for block in audit_blocks:
            if block.get("type") == "todo":
                content = block.get("content", "")
                properties = block.get("properties", {})
                is_checked = properties.get("checked", False) if isinstance(properties, dict) else False
                todos.append({"content": content, "checked": is_checked})
    
        if len(todos) < 3:
            errors.append(f"[X] Expected 3 todo items in Recent Updates, found {len(todos)}")
        else:
            checks_passed.append(f"[C] Found 3 todo items in Recent Updates as expected")
    
        # Check for specific todos
        button_found = any("button" in todo["content"].lower() for todo in todos)
        card_found = any("card" in todo["content"].lower() for todo in todos)
        table_found = any("table" in todo["content"].lower() for todo in todos)
    
        if not (button_found and card_found and table_found):
            errors.append("[X] Todo items should mention Button, Card, and Table components")
        else:
            checks_passed.append("[C] Todo items should mention Button, Card, and Table components")
    
        # Check that todos are unchecked
        checked_todos = [todo for todo in todos if todo["checked"]]
        if checked_todos:
            errors.append(f"[X] Todo items should be unchecked, found {len(checked_todos)} checked")
        else:
            checks_passed.append(f"[C] Todo items should be unchecked, found {len(checked_todos)} checked")
    
        # ALL requirements met!
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: add-structural-analysis-to-prd-v2
# Description: Add structural analysis callout and yaml metrics to PRD
# after specific sections
# =============================================================================
def _validate_agent_add_structural_analysis_to_prd(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate structural analysis additions with:
    - Gray callout with 📈 icon after 'User Stories - Part 2' heading
    - Callout contains section counts and calculated metrics
    - Code block with 'yaml' language after 'Overview - Part 2' section
    - Yaml contains actual counts for that section
    
    Returns 1.0 only if ALL requirements are met, otherwise 0.0
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Find the PRD page
    try:
        prd_pages = _get_pages_by_filter(backend, {"title": "Comprehensive Product Requirements Document"})
        if not prd_pages:
            errors.append("[X] Comprehensive Product Requirements Document page not found")
        else:
            checks_passed.append("[C] Comprehensive Product Requirements Document page found")
        prd_page = prd_pages[0]
    
        prd_id = prd_page.get("_id")
    
        # 2. Get all blocks for the page
        page_blocks = _get_blocks_by_filter(backend, {"pageId": prd_id})
    
        if len(page_blocks) < 10:
            errors.append(f"[X] PRD needs sufficient blocks, found {len(page_blocks)}")
        else:
            checks_passed.append(f"[C] PRD needs sufficient blocks, found {len(page_blocks)}")
    
        # Sort blocks by order
        blocks_by_order = sorted(
            [(block.get("order", 0), idx, block) for idx, block in enumerate(page_blocks)],
            key=lambda x: x[0]
        )
    
        # 3. Find 'User Stories - Part 2' heading
        user_stories_part2_order = -1
        for order, idx, block in blocks_by_order:
            if block.get("type") == "heading3":
                content = block.get("content", "")
                if "user stories" in content.lower() and "part 2" in content.lower():
                    user_stories_part2_order = order
                    break
    
        if user_stories_part2_order == -1:
            errors.append("[X] 'User Stories - Part 2' heading not found")
        else:
            checks_passed.append("[C] 'User Stories - Part 2' heading found")
    
        # 4. Validate gray callout with 📈 icon after User Stories Part 2
        gray_callout_found = False
        for order, idx, block in blocks_by_order:
            if block.get("type") == "callout" and order > user_stories_part2_order:
                properties = block.get("properties", {})
                bg_color = properties.get("backgroundColor", "") if isinstance(properties, dict) else ""
                icon = properties.get("icon", "") if isinstance(properties, dict) else ""
            
                if "gray" in bg_color.lower() and "📈" in str(icon):
                    content = block.get("content", "")
                    if "section analysis" in content.lower() and "heading blocks" in content.lower():
                        gray_callout_found = True
                        break
    
        if not gray_callout_found:
            errors.append("[X] Gray callout with 📈 icon and section analysis not found after 'User Stories - Part 2'")
        else:
            checks_passed.append("[C] Gray callout with 📈 icon and section analysis found after 'User Stories - Part 2'")
    
        # 5. Find 'Overview - Part 2' section
        overview_part2_order = -1
        for order, idx, block in blocks_by_order:
            if block.get("type") == "heading3":
                content = block.get("content", "")
                if "overview" in content.lower() and "part 2" in content.lower():
                    overview_part2_order = order
                    break
    
        if overview_part2_order == -1:
            errors.append("[X] 'Overview - Part 2' heading not found")
        else:
            checks_passed.append("[C] 'Overview - Part 2' heading found")
    
        # 6. Validate code block with 'yaml' language after Overview Part 2
        yaml_code_found = False
        for order, idx, block in blocks_by_order:
            if block.get("type") == "code" and order > overview_part2_order:
                properties = block.get("properties", {})
                language = properties.get("language", "") if isinstance(properties, dict) else ""
            
                if "yaml" in language.lower():
                    content = block.get("content", "")
                    if "metrics:" in content.lower() and "section_blocks:" in content.lower():
                        yaml_code_found = True
                        break
    
        if not yaml_code_found:
            errors.append("[X] Code block with 'yaml' language and metrics not found after 'Overview - Part 2'")
        else:
            checks_passed.append("[C] Code block with 'yaml' language and metrics found after 'Overview - Part 2'")
    
        # ALL requirements met!
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: add-time-estimates-to-sprint-todos-v2
# Description: Add time estimates section with quote blocks for each todo
# in Sprint Planning Jan 15 page
# =============================================================================
def _validate_agent_add_time_estimates_to_sprint_todos(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate time estimates section with:
    - Divider after last todo in Action Items
    - heading_3 '⏱️ Time Estimates'
    - Yellow callout with 📋 icon about time estimates
    - Quote blocks for each todo with estimate format
    
    Returns 1.0 only if ALL requirements are met, otherwise 0.0
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Find Sprint Planning page
    try:
        sprint_pages = _get_pages_by_filter(backend, {"title": "Sprint Planning - Jan 15"})
        if not sprint_pages:
            sprint_pages = _get_pages_by_filter(backend, {"title": "Sprint Planning"})
        if not sprint_pages:
            errors.append("[X] Sprint Planning - Jan 15 page not found")
        else:
            checks_passed.append("[C] Sprint Planning - Jan 15 page found")
        sprint_page = sprint_pages[0]
    
        sprint_id = sprint_page.get("_id")
    
        # 2. Get all blocks for the page
        page_blocks = _get_blocks_by_filter(backend, {"pageId": sprint_id})
    
        if len(page_blocks) < 5:
            errors.append(f"[X] Sprint Planning page needs sufficient blocks, found {len(page_blocks)}")
        else:
            checks_passed.append(f"[C] Sprint Planning page needs sufficient blocks, found {len(page_blocks)}")
    
        # Sort blocks by order
        blocks_by_order = sorted(
            [(block.get("order", 0), idx, block) for idx, block in enumerate(page_blocks)],
            key=lambda x: x[0]
        )
    
        # 3. Find Action Items heading
        action_items_order = -1
        for order, idx, block in blocks_by_order:
            if block.get("type") == "heading2":
                content = block.get("content", "")
                if "action items" in content.lower():
                    action_items_order = order
                    break
    
        if action_items_order == -1:
            errors.append("[X] 'Action Items' heading not found")
        else:
            checks_passed.append("[C] 'Action Items' heading found")
    
        # 4. Count todos in Action Items section
        todos = []
        for order, idx, block in blocks_by_order:
            if block.get("type") == "todo" and order > action_items_order:
                content = block.get("content", "")
                todos.append(content)
    
        if len(todos) < 1:
            errors.append("[X] No todos found in Action Items section")
        else:
            checks_passed.append("[C] todos found in Action Items section")
    
        # 5. Validate divider exists
        divider_found = False
        for block in page_blocks:
            if block.get("type") == "divider":
                divider_found = True
                break
    
        if not divider_found:
            errors.append("[X] Divider not found after Action Items todos")
        else:
            checks_passed.append("[C] Divider found after Action Items todos")
    
        # 6. Validate heading_3 '⏱️ Time Estimates'
        time_estimates_found = False
        for block in page_blocks:
            if block.get("type") == "heading3":
                content = block.get("content", "")
                if "⏱️" in content and "time estimates" in content.lower():
                    time_estimates_found = True
                    break
    
        if not time_estimates_found:
            errors.append("[X] heading_3 '⏱️ Time Estimates' not found")
        else:
            checks_passed.append("[C] heading_3 '⏱️ Time Estimates' found")
    
        # 7. Validate yellow callout with 📋 icon
        callout_found = False
        for block in page_blocks:
            if block.get("type") == "callout":
                properties = block.get("properties", {})
                bg_color = properties.get("backgroundColor", "") if isinstance(properties, dict) else ""
                icon = properties.get("icon", "") if isinstance(properties, dict) else ""
            
                if "yellow" in bg_color.lower() and "📋" in str(icon):
                    content = block.get("content", "")
                    if "time estimates" in content.lower() and "sprint planning" in content.lower():
                        callout_found = True
                        break
    
        if not callout_found:
            errors.append("[X] Yellow callout with 📋 icon about time estimates not found")
        else:
            checks_passed.append("[C] Yellow callout with 📋 icon about time estimates found")
    
        # 8. Validate quote blocks with estimate format
        quotes = []
        for block in page_blocks:
            if block.get("type") == "quote":
                content = block.get("content", "")
                if "estimated hours" in content.lower() or "[tbd]" in content.lower():
                    quotes.append(content)
    
        if len(quotes) < len(todos):
            errors.append(f"[X] Expected {len(todos)} quote blocks (one per todo), found {len(quotes)}")
        else:
            checks_passed.append(f"[C] Expected {len(todos)} quote blocks (one per todo), found {len(quotes)}")
    
        # ALL requirements met!
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: create-project-health-dashboard-v2
# Description: Create comprehensive Project Health Dashboard analyzing multiple pages
# =============================================================================
def _validate_agent_create_project_health_dashboard_2(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate Project Health Dashboard with:
    - Page under Project Documentation with 📊 icon
    - heading_1 '🏥 Project Health Dashboard'
    - Paragraph intro text
    - heading_2 '📈 Aggregate Metrics'
    - Four summaries with rotating callout colors analyzing Q1, Q2, Bug Tracker, Feature Requests
    - heading_2 '🎯 Overall Project Status' with markdown code block table
    - Quote block at end
    
    Returns 1.0 only if ALL requirements are met, otherwise 0.0
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Find Project Documentation page
    try:
        project_doc_pages = _get_pages_by_filter(backend, {"title": "Project Documentation"})
        if not project_doc_pages:
            errors.append("[X] Project Documentation page not found")
        else:
            checks_passed.append("[C] Project Documentation page found")
        project_doc = project_doc_pages[0]
    
        # 2. Find Project Health Dashboard page
        dashboard_pages = _get_pages_by_filter(backend, {"title": "Project Health Dashboard"})
        if not dashboard_pages:
            errors.append("[X] Project Health Dashboard page not found")
        else:
            checks_passed.append("[C] Project Health Dashboard page found")
        dashboard_page = dashboard_pages[0]
    
        dashboard_id = dashboard_page.get("_id")
    
        # 3. Check icon is 📊
        icon = dashboard_page.get("icon")
        if not icon:
            errors.append("[X] Project Health Dashboard page does not have an icon")
        else:
            checks_passed.append("[C] Project Health Dashboard page has an icon")
        icon_value = icon.get("value", "") if isinstance(icon, dict) else str(icon)
        if "📊" not in icon_value:
            errors.append(f"[X] Project Health Dashboard should have 📊 icon, found: {icon_value}")
        else:
            checks_passed.append(f"[C] Project Health Dashboard should have 📊 icon, found: {icon_value}")
    
        # 4. Verify it's a child of Project Documentation
        if not _check_page_is_child_of(project_doc, dashboard_page):
            errors.append("[X] Project Health Dashboard is not a child of Project Documentation")
        else:
            checks_passed.append("[C] Project Health Dashboard is a child of Project Documentation")
    
        # 5. Get blocks for dashboard
        dashboard_blocks = _get_blocks_by_filter(backend, {"pageId": dashboard_id})
    
        if len(dashboard_blocks) < 10:
            errors.append(f"[X] Dashboard needs multiple blocks, found {len(dashboard_blocks)}")
        else:
            checks_passed.append(f"[C] Dashboard needs multiple blocks, found {len(dashboard_blocks)}")
    
        # 6. Find required structural elements
        h1_found = False
        intro_paragraph_found = False
        h2_aggregate_found = False
        h2_overall_found = False
        quote_found = False
        markdown_code_found = False
        callouts_found = []
    
        for block in dashboard_blocks:
            block_type = block.get("type", "")
            block_content = block.get("content", "")
            block_properties = block.get("properties", {})
        
            # Check heading_1 '🏥 Project Health Dashboard'
            if block_type == "heading1" and "🏥" in block_content and "project health dashboard" in block_content.lower():
                h1_found = True
        
            # Check intro paragraph
            if block_type == "paragraph" and "real-time project status" in block_content.lower():
                intro_paragraph_found = True
        
            # Check heading_2 '📈 Aggregate Metrics'
            if block_type == "heading2" and "📈" in block_content and "aggregate metrics" in block_content.lower():
                h2_aggregate_found = True
        
            # Check heading_2 '🎯 Overall Project Status'
            if block_type == "heading2" and "🎯" in block_content and "overall project status" in block_content.lower():
                h2_overall_found = True
        
            # Check callouts with task summaries
            if block_type == "callout":
                bg_color = block_properties.get("backgroundColor", "") if isinstance(block_properties, dict) else ""
                content_lower = block_content.lower()
                if "tasks:" in content_lower and "done:" in content_lower and "pending:" in content_lower:
                    callouts_found.append(bg_color)
        
            # Check code block with markdown language
            if block_type == "code":
                code_lang = block_properties.get("language", "") if isinstance(block_properties, dict) else ""
                if "markdown" in code_lang.lower():
                    # Check for table with status icons
                    if ("✅" in block_content or "⚠️" in block_content or "❌" in block_content) and "%" in block_content:
                        markdown_code_found = True
        
            # Check quote block
            if block_type == "quote" and "what gets measured gets managed" in block_content.lower():
                quote_found = True
    
        # Validate all elements
        if not h1_found:
            errors.append("[X] heading_1 '🏥 Project Health Dashboard' not found")
        else:
            checks_passed.append("[C] heading_1 '🏥 Project Health Dashboard' found")
    
        if not intro_paragraph_found:
            errors.append("[X] Intro paragraph about real-time project status not found")
        else:
            checks_passed.append("[C] Intro paragraph about real-time project status found")
    
        if not h2_aggregate_found:
            errors.append("[X] heading_2 '📈 Aggregate Metrics' not found")
        else:
            checks_passed.append("[C] heading_2 '📈 Aggregate Metrics' found")
    
        if len(callouts_found) < 4:
            errors.append(f"[X] Expected 4 callouts with task summaries, found {len(callouts_found)}")
        else:
            checks_passed.append(f"[C] Found 4 callouts with task summaries as expected")
    
        # Check for rotating colors (blue, yellow, green, brown)
        expected_colors = ["blue", "yellow", "green", "brown"]
        colors_match = any(color in " ".join(callouts_found).lower() for color in expected_colors)
        if not colors_match:
            errors.append(f"[X] Callouts should have rotating colors (blue, yellow, green, brown), found: {callouts_found}")
        else:
            checks_passed.append(f"[C] Callouts should have rotating colors (blue, yellow, green, brown), found: {callouts_found}")
    
        if not h2_overall_found:
            errors.append("[X] heading_2 '🎯 Overall Project Status' not found")
        else:
            checks_passed.append("[C] heading_2 '🎯 Overall Project Status' found")
    
        if not markdown_code_found:
            errors.append("[X] Code block with markdown table showing percentages and status icons not found")
        else:
            checks_passed.append("[C] Code block with markdown table showing percentages and status icons found")
    
        if not quote_found:
            errors.append("[X] Quote block 'What gets measured gets managed' not found at end")
        else:
            checks_passed.append("[C] Quote block 'What gets measured gets managed' found at end")
    
        # ALL requirements met!
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: create-integrated-project-analytics-v2
# Description: Create sophisticated cross-project analysis system at root level
# =============================================================================
def _validate_agent_create_integrated_project_analytics(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate Integrated Project Analytics with:
    - Root level page with 📊 icon
    - heading_1 '🎯 Integrated Project Analytics'
    - Analyses of 5 pages: Q1, Q2, Bug Tracker, Feature Requests, Weekly Standup
    - heading_2 '🏆 Performance Summary' with markdown table
    - heading_2 '🎯 Aggregate Metrics' with conditional callout color
    - heading_3 '🔄 Last Updated' with timestamp
    
    Returns 1.0 only if ALL requirements are met, otherwise 0.0
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    # 1. Find Integrated Project Analytics page
    try:
        analytics_page = _find_page_by_title(final_state_backend, "Integrated Project Analytics")
        if not analytics_page:
            errors.append("[X] Integrated Project Analytics page not found")
        else:
            checks_passed.append("[C] Integrated Project Analytics page found")
    
        analytics_id = analytics_page.get("_id")
    
        # 2. Check icon is 📊
        icon = analytics_page.get("icon")
        if not icon:
            errors.append("[X] Integrated Project Analytics page does not have an icon")
        else:
            checks_passed.append("[C] Integrated Project Analytics page has an icon")
        icon_value = icon.get("value", "") if isinstance(icon, dict) else str(icon)
        if "📊" not in icon_value:
            errors.append(f"[X] Integrated Project Analytics should have 📊 icon, found: {icon_value}")
        else:
            checks_passed.append(f"[C] Integrated Project Analytics should have 📊 icon, found: {icon_value}")
    
        # 3. Check it's at root level (no parent or parent is null)
        parent_id = analytics_page.get("parentId") or analytics_page.get("parent_id")
        if parent_id and parent_id != "":
            errors.append("[X] Integrated Project Analytics should be at root level, not a child page")
        else:
            checks_passed.append("[C] Integrated Project Analytics should be at root level, a child page")
    
        # 4. Get blocks for analytics page
        analytics_blocks = _get_blocks_for_page(final_state_backend, analytics_id)
    
        if len(analytics_blocks) < 10:
            errors.append(f"[X] Analytics page needs multiple blocks, found {len(analytics_blocks)}")
        else:
            checks_passed.append(f"[C] Analytics page needs multiple blocks, found {len(analytics_blocks)}")
    
        # 5. Find required structural elements
        h1_found = False
        intro_paragraph_found = False
        h2_multi_project_found = False
        h2_performance_found = False
        h2_aggregate_found = False
        h3_last_updated_found = False
        markdown_code_found = False
        aggregate_callout_found = False
        project_analyses_count = 0
    
        for block in analytics_blocks:
            block_type = block.get("type", "")
            block_content = block.get("content", "")
            block_properties = block.get("properties", {})
        
            # Check heading_1
            if block_type == "heading1" and "🎯" in block_content and "integrated project analytics" in block_content.lower():
                h1_found = True
        
            # Check intro paragraph
            if block_type == "paragraph" and "real-time insights" in block_content.lower():
                intro_paragraph_found = True
        
            # Check heading_2 Multi-Project Task Analysis
            if block_type == "heading2" and "📈" in block_content and "multi-project task analysis" in block_content.lower():
                h2_multi_project_found = True
        
            # Count project analyses (heading_3 for each project)
            if block_type == "heading3":
                if any(proj in block_content for proj in ["Q1 Goals", "Q2 Goals", "Bug Tracker", "Feature Requests", "Weekly Standup"]):
                    project_analyses_count += 1
        
            # Check for status text with completion and emoji
            if block_type == "paragraph":
                content_lower = block_content.lower()
                if "status:" in content_lower and "tasks" in content_lower and "% complete" in content_lower:
                    if "✅" in block_content or "⚠️" in block_content or "❌" in block_content:
                        pass  # Valid status line
        
            # Check heading_2 Performance Summary
            if block_type == "heading2" and "🏆" in block_content and "performance summary" in block_content.lower():
                h2_performance_found = True
        
            # Check markdown code block
            if block_type == "code":
                code_lang = block_properties.get("language", "") if isinstance(block_properties, dict) else ""
                if "markdown" in code_lang.lower():
                    markdown_code_found = True
        
            # Check heading_2 Aggregate Metrics
            if block_type == "heading2" and "🎯" in block_content and "aggregate metrics" in block_content.lower():
                h2_aggregate_found = True
        
            # Check callout with aggregate metrics
            if block_type == "callout":
                content_lower = block_content.lower()
                if "overall project health" in content_lower and "/" in block_content and "%" in block_content:
                    aggregate_callout_found = True
        
            # Check heading_3 Last Updated
            if block_type == "heading3" and "🔄" in block_content and "last updated" in block_content.lower():
                h3_last_updated_found = True
    
        # Validate all elements
        if not h1_found:
            errors.append("[X] heading_1 '🎯 Integrated Project Analytics' not found")
        else:
            checks_passed.append("[C] heading_1 '🎯 Integrated Project Analytics' found")
    
        if not intro_paragraph_found:
            errors.append("[X] Intro paragraph about real-time insights not found")
        else:
            checks_passed.append("[C] Intro paragraph about real-time insights found")
    
        if not h2_multi_project_found:
            errors.append("[X] heading_2 '📈 Multi-Project Task Analysis' not found")
        else:
            checks_passed.append("[C] heading_2 '📈 Multi-Project Task Analysis' found")
    
        if project_analyses_count < 5:
            errors.append(f"[X] Expected 5 project analyses (Q1, Q2, Bug Tracker, Feature Requests, Weekly Standup), found {project_analyses_count}")
        else:
            checks_passed.append(f"[C] Expected 5 project analyses (Q1, Q2, Bug Tracker, Feature Requests, Weekly Standup), found {project_analyses_count}")
    
        if not h2_performance_found:
            errors.append("[X] heading_2 '🏆 Performance Summary' not found")
        else:
            checks_passed.append("[C] heading_2 '🏆 Performance Summary' found")
    
        if not markdown_code_found:
            errors.append("[X] Code block with markdown summary table not found")
        else:
            checks_passed.append("[C] Code block with markdown summary table found")
    
        if not h2_aggregate_found:
            errors.append("[X] heading_2 '🎯 Aggregate Metrics' not found")
        else:
            checks_passed.append("[C] heading_2 '🎯 Aggregate Metrics' found")
    
        if not aggregate_callout_found:
            errors.append("[X] Callout with aggregate metrics (Overall Project Health) not found")
        else:
            checks_passed.append("[C] Callout with aggregate metrics (Overall Project Health) found")
    
        if not h3_last_updated_found:
            errors.append("[X] heading_3 '🔄 Last Updated' with timestamp not found")
        else:
            checks_passed.append("[C] heading_3 '🔄 Last Updated' with timestamp found")
    
        # ALL requirements met!
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: update-getting-started-quick-start-progress-v2
# Description: Update Getting Started page with progress tracking and tips
# =============================================================================
def _validate_agent_update_getting_started_quick_start_progress(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate Getting Started updates with:
    - Progress paragraph showing completion stats (2 of 4 completed - 50%)
    - Yellow callout after 'Try different block types' todo
    - Yellow callout after 'Share a page' todo
    - Both callouts have 💡 icon
    - All todos remain in original order
    
    Returns 1.0 only if ALL requirements are met, otherwise 0.0
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Find Getting Started page
    try:
        getting_started_pages = _get_pages_by_filter(backend, {"title": "Getting Started"})
        if not getting_started_pages:
            errors.append("[X] Getting Started page not found")
        else:
            checks_passed.append("[C] Getting Started page found")
        getting_started = getting_started_pages[0]
    
        getting_started_id = getting_started.get("_id")
    
        # 2. Get blocks for page
        page_blocks = _get_blocks_by_filter(backend, {"pageId": getting_started_id})
    
        if len(page_blocks) < 5:
            errors.append(f"[X] Getting Started page needs sufficient blocks, found {len(page_blocks)}")
        else:
            checks_passed.append(f"[C] Getting Started page needs sufficient blocks, found {len(page_blocks)}")
    
        # 3. Find Quick Start Checklist heading and verify progress paragraph
        progress_found = False
        callout_after_try_blocks = False
        callout_after_share_page = False
        todos_count = 0
    
        for idx, block in enumerate(page_blocks):
            block_type = block.get("type", "")
            block_content = block.get("content", "")
            block_properties = block.get("properties", {})
        
            # Check for progress paragraph
            if block_type == "paragraph":
                content_lower = block_content.lower()
                if "progress:" in content_lower and "of" in content_lower and "completed" in content_lower and "%" in block_content:
                    # Verify it shows 2 of 4 completed (50%)
                    if "2" in block_content and "4" in block_content and "50" in block_content:
                        progress_found = True
        
            # Count todos
            if block_type == "todo":
                todos_count += 1
            
                # Check for callout after 'Try different block types' todo
                if "try different block types" in block_content.lower():
                    # Look for callout in next few blocks
                    for next_idx in range(idx + 1, min(idx + 3, len(page_blocks))):
                        next_block = page_blocks[next_idx]
                        if next_block.get("type") == "callout":
                            next_properties = next_block.get("properties", {})
                            bg_color = next_properties.get("backgroundColor", "") if isinstance(next_properties, dict) else ""
                            icon = next_properties.get("icon", "") if isinstance(next_properties, dict) else ""
                            content = next_block.get("content", "")
                        
                            if "yellow" in bg_color.lower() and "💡" in str(icon):
                                if "tip:" in content.lower() and "headings" in content.lower():
                                    callout_after_try_blocks = True
            
                # Check for callout after 'Share a page' todo
                if "share a page" in block_content.lower():
                    # Look for callout in next few blocks
                    for next_idx in range(idx + 1, min(idx + 3, len(page_blocks))):
                        next_block = page_blocks[next_idx]
                        if next_block.get("type") == "callout":
                            next_properties = next_block.get("properties", {})
                            bg_color = next_properties.get("backgroundColor", "") if isinstance(next_properties, dict) else ""
                            icon = next_properties.get("icon", "") if isinstance(next_properties, dict) else ""
                            content = next_block.get("content", "")
                        
                            if "yellow" in bg_color.lower() and "💡" in str(icon):
                                if "tip:" in content.lower() and "share button" in content.lower():
                                    callout_after_share_page = True
    
        # Validate all elements
        if not progress_found:
            errors.append("[X] Progress paragraph showing 'Progress: 2 of 4 completed (50%)' not found")
        else:
            checks_passed.append("[C] Progress paragraph showing 'Progress: 2 of 4 completed (50%)' found")
    
        if not callout_after_try_blocks:
            errors.append("[X] Yellow callout with 💡 icon after 'Try different block types' todo not found or incorrect")
        else:
            checks_passed.append("[C] Yellow callout with 💡 icon after 'Try different block types' todo found or incorrect")
    
        if not callout_after_share_page:
            errors.append("[X] Yellow callout with 💡 icon after 'Share a page' todo not found or incorrect")
        else:
            checks_passed.append("[C] Yellow callout with 💡 icon after 'Share a page' todo found or incorrect")
    
        if todos_count < 4:
            errors.append(f"[X] Expected at least 4 todos in Quick Start Checklist, found {todos_count}")
        else:
            checks_passed.append(f"[C] Found at least 4 todos in Quick Start Checklist ({todos_count})")
    
        # ALL requirements met!
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: add-bug-analysis-dashboard-v2
# Description: Add Bug Analysis Dashboard to Bug Tracker page
# =============================================================================
def _validate_agent_add_bug_analysis_dashboard_2(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate Bug Analysis Dashboard with:
    - heading_2 '🔍 Bug Analysis Dashboard' after Low Priority section
    - Paragraph with today's date
    - Numbered list with bug counts by priority
    - Divider
    - Callout with conditional color (red for critical bugs, green otherwise)
    - Quote at end
    
    Returns 1.0 only if ALL requirements are met, otherwise 0.0
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Find Bug Tracker page
    try:
        bug_tracker_pages = _get_pages_by_filter(backend, {"title": "Bug Tracker"})
        if not bug_tracker_pages:
            errors.append("[X] Bug Tracker page not found")
        else:
            checks_passed.append("[C] Bug Tracker page found")
        bug_tracker = bug_tracker_pages[0]
    
        bug_tracker_id = bug_tracker.get("_id")
    
        # 2. Get blocks for page
        page_blocks = _get_blocks_by_filter(backend, {"pageId": bug_tracker_id})
    
        if len(page_blocks) < 5:
            errors.append(f"[X] Bug Tracker page needs sufficient blocks, found {len(page_blocks)}")
        else:
            checks_passed.append(f"[C] Bug Tracker page needs sufficient blocks, found {len(page_blocks)}")
    
        # 3. Find required structural elements
        h2_analysis_found = False
        date_paragraph_found = False
        numbered_list_found = False
        divider_found = False
        callout_found = False
        quote_found = False
    
        # Track if we're after Low Priority section
        found_low_priority = False
    
        for block in page_blocks:
            block_type = block.get("type", "")
            block_content = block.get("content", "")
            block_properties = block.get("properties", {})
        
            # Check for Low Priority heading
            if block_type == "heading2" and "low priority" in block_content.lower():
                found_low_priority = True
        
            # After Low Priority, check for Bug Analysis Dashboard
            if found_low_priority and block_type == "heading2" and "🔍" in block_content and "bug analysis dashboard" in block_content.lower():
                h2_analysis_found = True
        
            # Check for date paragraph
            if block_type == "paragraph":
                content_lower = block_content.lower()
                if "real-time bug statistics" in content_lower or ("as of" in content_lower and ("202" in block_content or "january" in content_lower)):
                    date_paragraph_found = True
        
            # Check for numbered list with bug priorities
            if block_type == "numberedList":
                content_lower = block_content.lower()
                if ("critical" in content_lower or "medium" in content_lower or "low priority" in content_lower) and "total" in content_lower:
                    numbered_list_found = True
        
            # Check for divider
            if block_type == "divider":
                divider_found = True
        
            # Check for callout with system stability
            if block_type == "callout":
                content_lower = block_content.lower()
                if "system stability" in content_lower or "critical" in content_lower or "stable" in content_lower:
                    bg_color = block_properties.get("backgroundColor", "") if isinstance(block_properties, dict) else ""
                    icon = block_properties.get("icon", "") if isinstance(block_properties, dict) else ""
                
                    # Should be red with 🚨 or green with ✅
                    if ("red" in bg_color.lower() and "🚨" in str(icon)) or ("green" in bg_color.lower() and "✅" in str(icon)):
                        callout_found = True
        
            # Check for quote
            if block_type == "quote" and "bug fixed today" in block_content.lower():
                quote_found = True
    
        # Validate all elements
        if not h2_analysis_found:
            errors.append("[X] heading_2 '🔍 Bug Analysis Dashboard' not found after Low Priority section")
        else:
            checks_passed.append("[C] heading_2 '🔍 Bug Analysis Dashboard' found after Low Priority section")
    
        if not date_paragraph_found:
            errors.append("[X] Paragraph with date/statistics not found")
        else:
            checks_passed.append("[C] Paragraph with date/statistics found")
    
        if not numbered_list_found:
            errors.append("[X] Numbered list with bug analysis by priority not found")
        else:
            checks_passed.append("[C] Numbered list with bug analysis by priority found")
    
        if not divider_found:
            errors.append("[X] Divider not found in Bug Analysis Dashboard")
        else:
            checks_passed.append("[C] Divider found in Bug Analysis Dashboard")
    
        if not callout_found:
            errors.append("[X] Callout with system stability status (red/🚨 or green/✅) not found")
        else:
            checks_passed.append("[C] Callout with system stability status (red/🚨 or green/✅) found")
    
        if not quote_found:
            errors.append("[X] Quote 'A bug fixed today saves ten tomorrow' not found")
        else:
            checks_passed.append("[C] Quote 'A bug fixed today saves ten tomorrow' found")
    
        # ALL requirements met!
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: modify-onboarding-guide-first-week-goals-v2
# Description: Add divider, emoji prefixes, callout, and bookmark to Onboarding Guide
# =============================================================================
def _validate_agent_modify_onboarding_guide_first_week_goals(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate Onboarding Guide modifications with:
    - Divider immediately before 'First Week Goals'
    - Numbered list items with emoji prefixes
    - Purple callout with buddy system tip
    - Bookmark linking to Team Directory
    
    Returns 1.0 only if ALL requirements are met, otherwise 0.0
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    # 1. Find Onboarding Guide page
    try:
        onboarding_guide = _find_page_by_title(final_state_backend, "Onboarding Guide")
        if not onboarding_guide:
            errors.append("[X] Onboarding Guide page not found")
        else:
            checks_passed.append("[C] Onboarding Guide page found")
    
        onboarding_guide_id = onboarding_guide.get("_id")
    
        # 2. Get blocks for page
        page_blocks = _get_blocks_for_page(final_state_backend, onboarding_guide_id)
    
        if len(page_blocks) < 5:
            errors.append(f"[X] Onboarding Guide page needs sufficient blocks, found {len(page_blocks)}")
        else:
            checks_passed.append(f"[C] Onboarding Guide page needs sufficient blocks, found {len(page_blocks)}")
    
        # 3. Find required structural elements
        divider_before_first_week = False
        emoji_training = False
        emoji_meetings = False
        emoji_dev_env = False
        purple_callout = False
        bookmark_team_directory = False
    
        first_week_idx = -1
    
        for idx, block in enumerate(page_blocks):
            block_type = block.get("type", "")
            block_content = block.get("content", "")
            block_properties = block.get("properties", {})
        
            # Find First Week Goals heading
            if block_type == "heading2" and "first week goals" in block_content.lower():
                first_week_idx = idx
            
                # Check if previous block is divider
                if idx > 0 and page_blocks[idx - 1].get("type") == "divider":
                    divider_before_first_week = True
        
            # Check for numbered list items with emoji prefixes
            if block_type == "numberedList":
                if "📚" in block_content and "training modules" in block_content.lower():
                    emoji_training = True
                if "👥" in block_content and "1:1 meetings" in block_content.lower():
                    emoji_meetings = True
                if "💻" in block_content and "development environment" in block_content.lower():
                    emoji_dev_env = True
        
            # Check for purple callout with buddy system tip
            if block_type == "callout":
                bg_color = block_properties.get("backgroundColor", "") if isinstance(block_properties, dict) else ""
                content_lower = block_content.lower()
            
                if "purple" in bg_color.lower() and "💡" in block_content:
                    if "buddy system" in content_lower and "team directory" in content_lower:
                        purple_callout = True
        
            # Check for bookmark to Team Directory
            if block_type == "bookmark":
                content_lower = block_content.lower()
                url = block_properties.get("url", "") if isinstance(block_properties, dict) else ""
            
                if "team directory" in content_lower or "team directory" in url.lower():
                    bookmark_team_directory = True
    
        # Validate all elements
        if first_week_idx == -1:
            errors.append("[X] 'First Week Goals' heading not found")
        else:
            checks_passed.append("[C] 'First Week Goals' heading found")
    
        if not divider_before_first_week:
            errors.append("[X] Divider not found immediately before 'First Week Goals' heading")
        else:
            checks_passed.append("[C] Divider found immediately before 'First Week Goals' heading")
    
        if not emoji_training:
            errors.append("[X] Numbered list item with 📚 emoji for training modules not found")
        else:
            checks_passed.append("[C] Numbered list item with 📚 emoji for training modules found")
    
        if not emoji_meetings:
            errors.append("[X] Numbered list item with 👥 emoji for 1:1 meetings not found")
        else:
            checks_passed.append("[C] Numbered list item with 👥 emoji for 1:1 meetings found")
    
        if not emoji_dev_env:
            errors.append("[X] Numbered list item with 💻 emoji for development environment not found")
        else:
            checks_passed.append("[C] Numbered list item with 💻 emoji for development environment found")
    
        if not purple_callout:
            errors.append("[X] Purple callout with 💡 icon about buddy system not found")
        else:
            checks_passed.append("[C] Purple callout with 💡 icon about buddy system found")
    
        if not bookmark_team_directory:
            errors.append("[X] Bookmark linking to Team Directory not found")
        else:
            checks_passed.append("[C] Bookmark linking to Team Directory found")
    
        # ALL requirements met!
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: add-week-january-22-to-standup-template-v2
# Description: Add new week section to Weekly Standup Template
# =============================================================================
def _validate_agent_add_week_january_22_to_standup_template(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate Weekly Standup Template additions with:
    - heading_2 'Week of January 22, 2024' after Blockers heading
    - heading_3 '✅ Completed This Week' with 3 checked todos
    - heading_3 '⏳ In Progress' with 2 unchecked todos
    - All todos have correct emoji prefixes and text
    
    Returns 1.0 only if ALL requirements are met, otherwise 0.0
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Find Weekly Standup Template page
    try:
        standup_pages = _get_pages_by_filter(backend, {"title": "Weekly Standup Template"})
        if not standup_pages:
            standup_pages = _get_pages_by_filter(backend, {"title": "Weekly Standup"})
        if not standup_pages:
            errors.append("[X] Weekly Standup Template page not found")
        else:
            checks_passed.append("[C] Weekly Standup Template page found")
        standup_page = standup_pages[0]
    
        standup_id = standup_page.get("_id")
    
        # 2. Get blocks for page
        page_blocks = _get_blocks_by_filter(backend, {"pageId": standup_id})
    
        if len(page_blocks) < 5:
            errors.append(f"[X] Weekly Standup Template page needs sufficient blocks, found {len(page_blocks)}")
        else:
            checks_passed.append(f"[C] Weekly Standup Template page needs sufficient blocks, found {len(page_blocks)}")
    
        # 3. Find required structural elements
        h2_january_22_found = False
        h3_completed_found = False
        h3_in_progress_found = False
    
        completed_todos = []
        in_progress_todos = []
    
        blockers_idx = -1
        january_22_idx = -1
    
        for idx, block in enumerate(page_blocks):
            block_type = block.get("type", "")
            block_content = block.get("content", "")
        
            # Find Blockers heading
            if block_type == "heading2" and "blockers" in block_content.lower():
                blockers_idx = idx
        
            # Find Week of January 22, 2024 heading
            if block_type == "heading2" and "week of january 22, 2024" in block_content.lower():
                h2_january_22_found = True
                january_22_idx = idx
        
            # Find Completed This Week heading
            if block_type == "heading3" and "✅" in block_content and "completed this week" in block_content.lower():
                h3_completed_found = True
        
            # Find In Progress heading
            if block_type == "heading3" and "⏳" in block_content and "in progress" in block_content.lower():
                h3_in_progress_found = True
        
            # Count todos
            if block_type == "todo":
                checked = block.get("properties", {}).get("checked", False)
            
                # Check for specific completed todos
                if checked:
                    if "🎯" in block_content and "authentication microservice" in block_content.lower():
                        completed_todos.append("auth")
                    if "📱" in block_content and "mobile app crashes" in block_content.lower():
                        completed_todos.append("mobile")
                    if "🔧" in block_content and "database queries" in block_content.lower():
                        completed_todos.append("database")
                else:
                    # Check for in progress todos
                    if "🚀" in block_content and "websocket" in block_content.lower():
                        in_progress_todos.append("websocket")
                    if "📊" in block_content and "analytics dashboard" in block_content.lower():
                        in_progress_todos.append("analytics")
    
        # Validate all elements
        if not h2_january_22_found:
            errors.append("[X] heading_2 'Week of January 22, 2024' not found")
        else:
            checks_passed.append("[C] heading_2 'Week of January 22, 2024' found")
    
        # Verify it's after Blockers heading
        if blockers_idx != -1 and january_22_idx != -1 and january_22_idx <= blockers_idx:
            errors.append("[X] 'Week of January 22, 2024' should appear after 'Blockers' heading")
        else:
            checks_passed.append("[C] 'Week of January 22, 2024' should appear after 'Blockers' heading")
    
        if not h3_completed_found:
            errors.append("[X] heading_3 '✅ Completed This Week' not found")
        else:
            checks_passed.append("[C] heading_3 '✅ Completed This Week' found")
    
        if len(completed_todos) < 3:
            errors.append(f"[X] Expected 3 checked todos under 'Completed This Week', found {len(completed_todos)}")
        else:
            checks_passed.append(f"[C] Found 3 checked todos under 'Completed This Week' as expected")
    
        if not h3_in_progress_found:
            errors.append("[X] heading_3 '⏳ In Progress' not found")
        else:
            checks_passed.append("[C] heading_3 '⏳ In Progress' found")
    
        if len(in_progress_todos) < 2:
            errors.append(f"[X] Expected 2 unchecked todos under 'In Progress', found {len(in_progress_todos)}")
        else:
            checks_passed.append(f"[C] Found 2 unchecked todos under 'In Progress' as expected")
    
        # ALL requirements met!
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: add-code-review-checklist-to-engineering-wiki-v2
# Description: Add Code Review Checklist with toggle blocks
# =============================================================================
def _validate_agent_add_code_review_checklist_to_engineering_wiki(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate Code Review Checklist with:
    - heading_2 '✅ Code Review Checklist' after API Patterns
    - Paragraph intro
    - Toggle '🔍 Frontend Checklist' with 4 unchecked todos
    - Toggle '🔧 Backend Checklist' with 3 todos
    - Red callout with ⚠️ icon about merging requirements
    
    Returns 1.0 only if ALL requirements are met, otherwise 0.0
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    # 1. Find Engineering Wiki page
    try:
        engineering_wiki = _find_page_by_title(final_state_backend, "Engineering Wiki")
        if not engineering_wiki:
            errors.append("[X] Engineering Wiki page not found")
        else:
            checks_passed.append("[C] Engineering Wiki page found")
    
        engineering_wiki_id = engineering_wiki.get("_id")
    
        # 2. Get blocks for page
        page_blocks = _get_blocks_for_page(final_state_backend, engineering_wiki_id)
    
        if len(page_blocks) < 5:
            errors.append(f"[X] Engineering Wiki page needs sufficient blocks, found {len(page_blocks)}")
        else:
            checks_passed.append(f"[C] Engineering Wiki page needs sufficient blocks, found {len(page_blocks)}")
    
        # 3. Find required structural elements
        h2_checklist_found = False
        intro_paragraph_found = False
        toggle_frontend_found = False
        toggle_backend_found = False
        red_callout_found = False
    
        frontend_todos_count = 0
        backend_todos_count = 0
    
        for block in page_blocks:
            block_type = block.get("type", "")
            block_content = block.get("content", "")
            block_properties = block.get("properties", {})
        
            # Check heading_2 Code Review Checklist
            if block_type == "heading2" and "✅" in block_content and "code review checklist" in block_content.lower():
                h2_checklist_found = True
        
            # Check intro paragraph
            if block_type == "paragraph":
                content_lower = block_content.lower()
                if "ensure all items are verified" in content_lower or ("verified" in content_lower and "approval" in content_lower):
                    intro_paragraph_found = True
        
            # Check toggle Frontend Checklist
            if block_type == "toggle" and "🔍" in block_content and "frontend checklist" in block_content.lower():
                toggle_frontend_found = True
        
            # Check toggle Backend Checklist
            if block_type == "toggle" and "🔧" in block_content and "backend checklist" in block_content.lower():
                toggle_backend_found = True
        
            # Count todos (would need to check child blocks of toggles in real implementation)
            if block_type == "todo":
                content_lower = block_content.lower()
                # Check for specific frontend todos
                if "⚛️" in block_content or "🎨" in block_content or "♿" in block_content or "📱" in block_content:
                    if "react" in content_lower or "css" in content_lower or "accessibility" in content_lower or "responsive" in content_lower:
                        frontend_todos_count += 1
            
                # Check for specific backend todos
                if "🔒" in block_content or "⚡" in block_content or "📝" in block_content:
                    if "security" in content_lower or "performance" in content_lower or "api documentation" in content_lower:
                        backend_todos_count += 1
        
            # Check red callout with merge warning
            if block_type == "callout":
                bg_color = block_properties.get("backgroundColor", "") if isinstance(block_properties, dict) else ""
                icon = block_properties.get("icon", "") if isinstance(block_properties, dict) else ""
                content_lower = block_content.lower()
            
                if "red" in bg_color.lower() and "⚠️" in str(icon):
                    if "checked" in content_lower and "merging" in content_lower:
                        red_callout_found = True
    
        # Validate all elements
        if not h2_checklist_found:
            errors.append("[X] heading_2 '✅ Code Review Checklist' not found")
        else:
            checks_passed.append("[C] heading_2 '✅ Code Review Checklist' found")
    
        if not intro_paragraph_found:
            errors.append("[X] Intro paragraph about verification before approval not found")
        else:
            checks_passed.append("[C] Intro paragraph about verification before approval found")
    
        if not toggle_frontend_found:
            errors.append("[X] Toggle '🔍 Frontend Checklist' not found")
        else:
            checks_passed.append("[C] Toggle '🔍 Frontend Checklist' found")
    
        if not toggle_backend_found:
            errors.append("[X] Toggle '🔧 Backend Checklist' not found")
        else:
            checks_passed.append("[C] Toggle '🔧 Backend Checklist' found")
    
        if frontend_todos_count < 4:
            errors.append(f"[X] Expected 4 todos in Frontend Checklist, found {frontend_todos_count}")
        else:
            checks_passed.append(f"[C] Found 4 todos in Frontend Checklist as expected")
    
        if backend_todos_count < 3:
            errors.append(f"[X] Expected 3 todos in Backend Checklist, found {backend_todos_count}")
        else:
            checks_passed.append(f"[C] Found 3 todos in Backend Checklist as expected")
    
        if not red_callout_found:
            errors.append("[X] Red callout with ⚠️ icon about merging requirements not found")
        else:
            checks_passed.append("[C] Red callout with ⚠️ icon about merging requirements found")
    
        # ALL requirements met!
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: add-security-implementation-checklist-v2
# Description: Add security section to Project Guidelines page
# =============================================================================
def _validate_agent_add_security_implementation_checklist(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate Security Implementation Checklist with:
    - Divider before heading_2
    - heading_2 '🔐 Security Implementation Checklist'
    - 3 unchecked todos with specific security items
    - Purple callout with 📋 icon about quarterly audits
    
    Returns 1.0 only if ALL requirements are met, otherwise 0.0
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Find Project Guidelines & Best Practices page
    try:
        guidelines_pages = _get_pages_by_filter(backend, {"title": "Project Guidelines & Best Practices"})
        if not guidelines_pages:
            guidelines_pages = _get_pages_by_filter(backend, {"title": "Project Guidelines"})
        if not guidelines_pages:
            errors.append("[X] Project Guidelines & Best Practices page not found")
        else:
            checks_passed.append("[C] Project Guidelines & Best Practices page found")
        guidelines_page = guidelines_pages[0]
    
        guidelines_id = guidelines_page.get("_id")
    
        # 2. Get blocks for page
        page_blocks = _get_blocks_by_filter(backend, {"pageId": guidelines_id})
    
        if len(page_blocks) < 5:
            errors.append(f"[X] Project Guidelines page needs sufficient blocks, found {len(page_blocks)}")
        else:
            checks_passed.append(f"[C] Project Guidelines page needs sufficient blocks, found {len(page_blocks)}")
    
        # 3. Find required structural elements
        divider_found = False
        h2_security_found = False
        security_todos = []
        purple_callout_found = False
    
        h2_security_idx = -1
    
        for idx, block in enumerate(page_blocks):
            block_type = block.get("type", "")
            block_content = block.get("content", "")
            block_properties = block.get("properties", {})
        
            # Find Security Implementation Checklist heading
            if block_type == "heading2" and "🔐" in block_content and "security implementation checklist" in block_content.lower():
                h2_security_found = True
                h2_security_idx = idx
            
                # Check if previous block is divider
                if idx > 0 and page_blocks[idx - 1].get("type") == "divider":
                    divider_found = True
        
            # Check for specific security todos
            if block_type == "todo":
                content_lower = block_content.lower()
                if "🛡️" in block_content and "https" in content_lower:
                    security_todos.append("https")
                if "🔍" in block_content and "input validation" in content_lower:
                    security_todos.append("validation")
                if "🚫" in block_content and "rate limiting" in content_lower:
                    security_todos.append("rate_limiting")
        
            # Check for purple callout with quarterly audits
            if block_type == "callout":
                bg_color = block_properties.get("backgroundColor", "") if isinstance(block_properties, dict) else ""
                icon = block_properties.get("icon", "") if isinstance(block_properties, dict) else ""
                content_lower = block_content.lower()
            
                if "purple" in bg_color.lower() and "📋" in str(icon):
                    if "security audits" in content_lower and "quarterly" in content_lower:
                        purple_callout_found = True
    
        # Validate all elements
        if not h2_security_found:
            errors.append("[X] heading_2 '🔐 Security Implementation Checklist' not found")
        else:
            checks_passed.append("[C] heading_2 '🔐 Security Implementation Checklist' found")
    
        if not divider_found:
            errors.append("[X] Divider not found immediately before Security Implementation Checklist heading")
        else:
            checks_passed.append("[C] Divider found immediately before Security Implementation Checklist heading")
    
        if len(security_todos) < 3:
            errors.append(f"[X] Expected 3 security todos (HTTPS, input validation, rate limiting), found {len(security_todos)}")
        else:
            checks_passed.append(f"[C] Expected 3 security todos (HTTPS, input validation, rate limiting), found {len(security_todos)}")
    
        if not purple_callout_found:
            errors.append("[X] Purple callout with 📋 icon about quarterly security audits not found")
        else:
            checks_passed.append("[C] Purple callout with 📋 icon about quarterly security audits found")
    
        # ALL requirements met!
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: create-engineering-best-practices-page-v2
# Description: Create comprehensive Engineering Best Practices page under Engineering Wiki
# =============================================================================
def _validate_agent_create_engineering_best_practices_page(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate Engineering Best Practices page with:
    - Page as child of Engineering Wiki
    - heading_1 '🛠️ Engineering Best Practices'
    - Quote block with Cory House quote
    - heading_2 '📝 Code Review Guidelines' with numbered list (3 items)
    - heading_2 '🔒 Security Checklist' with 4 unchecked todos
    - Red callout with ⚠️ icon about production deployments
    - heading_2 '🚀 Deployment Process' with bash code block
    
    Returns 1.0 only if ALL requirements are met, otherwise 0.0
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Find Engineering Wiki page
    try:
        engineering_wiki_pages = _get_pages_by_filter(backend, {"title": "Engineering Wiki"})
        if not engineering_wiki_pages:
            errors.append("[X] Engineering Wiki page not found")
        else:
            checks_passed.append("[C] Engineering Wiki page found")
        engineering_wiki = engineering_wiki_pages[0]
    
        # 2. Find Engineering Best Practices page
        best_practices_pages = _get_pages_by_filter(backend, {"title": "Engineering Best Practices"})
        if not best_practices_pages:
            errors.append("[X] Engineering Best Practices page not found")
        else:
            checks_passed.append("[C] Engineering Best Practices page found")
        best_practices_page = best_practices_pages[0]
    
        best_practices_id = best_practices_page.get("_id")
    
        # 3. Verify it's a child of Engineering Wiki
        if not _check_page_is_child_of(engineering_wiki, best_practices_page):
            errors.append("[X] Engineering Best Practices is not a child of Engineering Wiki")
        else:
            checks_passed.append("[C] Engineering Best Practices is a child of Engineering Wiki")
    
        # 4. Get blocks for page
        page_blocks = _get_blocks_by_filter(backend, {"pageId": best_practices_id})
    
        if len(page_blocks) < 8:
            errors.append(f"[X] Engineering Best Practices page needs multiple blocks, found {len(page_blocks)}")
        else:
            checks_passed.append(f"[C] Engineering Best Practices page needs multiple blocks, found {len(page_blocks)}")
    
        # 5. Find required structural elements
        h1_found = False
        quote_cory_house = False
        h2_code_review = False
        h2_security = False
        h2_deployment = False
        red_callout_found = False
        bash_code_found = False
    
        numbered_list_count = 0
        security_todos_count = 0
    
        for block in page_blocks:
            block_type = block.get("type", "")
            block_content = block.get("content", "")
            block_properties = block.get("properties", {})
        
            # Check heading_1
            if block_type == "heading1" and "🛠️" in block_content and "engineering best practices" in block_content.lower():
                h1_found = True
        
            # Check Cory House quote
            if block_type == "quote":
                content_lower = block_content.lower()
                if "code is like humor" in content_lower and "cory house" in content_lower:
                    quote_cory_house = True
        
            # Check heading_2 Code Review Guidelines
            if block_type == "heading2" and "📝" in block_content and "code review guidelines" in block_content.lower():
                h2_code_review = True
        
            # Count numbered list items
            if block_type == "numberedList":
                content_lower = block_content.lower()
                if "pr" in content_lower or "approvals" in content_lower or "tests" in content_lower or "documentation" in content_lower:
                    numbered_list_count += 1
        
            # Check heading_2 Security Checklist
            if block_type == "heading2" and "🔒" in block_content and "security checklist" in block_content.lower():
                h2_security = True
        
            # Count security todos
            if block_type == "todo":
                content_lower = block_content.lower()
                if "🔐" in block_content or "🚫" in block_content or "📊" in block_content or "🛡️" in block_content:
                    if "validate" in content_lower or "secrets" in content_lower or "log" in content_lower or "sql" in content_lower:
                        security_todos_count += 1
        
            # Check red callout
            if block_type == "callout":
                bg_color = block_properties.get("backgroundColor", "") if isinstance(block_properties, dict) else ""
                icon = block_properties.get("icon", "") if isinstance(block_properties, dict) else ""
                content_lower = block_content.lower()
            
                if "red" in bg_color.lower() and "⚠️" in str(icon):
                    if "critical" in content_lower and "production" in content_lower and "security scan" in content_lower:
                        red_callout_found = True
        
            # Check heading_2 Deployment Process
            if block_type == "heading2" and "🚀" in block_content and "deployment process" in block_content.lower():
                h2_deployment = True
        
            # Check bash code block
            if block_type == "code":
                code_lang = block_properties.get("language", "") if isinstance(block_properties, dict) else ""
                if "bash" in code_lang.lower():
                    content_lower = block_content.lower()
                    if "run_tests" in content_lower and "deploy" in content_lower:
                        bash_code_found = True
    
        # Validate all elements
        if not h1_found:
            errors.append("[X] heading_1 '🛠️ Engineering Best Practices' not found")
        else:
            checks_passed.append("[C] heading_1 '🛠️ Engineering Best Practices' found")
    
        if not quote_cory_house:
            errors.append("[X] Quote block with Cory House quote not found")
        else:
            checks_passed.append("[C] Quote block with Cory House quote found")
    
        if not h2_code_review:
            errors.append("[X] heading_2 '📝 Code Review Guidelines' not found")
        else:
            checks_passed.append("[C] heading_2 '📝 Code Review Guidelines' found")
    
        if numbered_list_count < 3:
            errors.append(f"[X] Expected 3 numbered list items for code review guidelines, found {numbered_list_count}")
        else:
            checks_passed.append(f"[C] Found 3 numbered list items for code review guidelines as expected")
    
        if not h2_security:
            errors.append("[X] heading_2 '🔒 Security Checklist' not found")
        else:
            checks_passed.append("[C] heading_2 '🔒 Security Checklist' found")
    
        if security_todos_count < 4:
            errors.append(f"[X] Expected 4 security todos, found {security_todos_count}")
        else:
            checks_passed.append(f"[C] Found 4 security todos as expected")
    
        if not red_callout_found:
            errors.append("[X] Red callout with ⚠️ icon about production deployments not found")
        else:
            checks_passed.append("[C] Red callout with ⚠️ icon about production deployments found")
    
        if not h2_deployment:
            errors.append("[X] heading_2 '🚀 Deployment Process' not found")
        else:
            checks_passed.append("[C] heading_2 '🚀 Deployment Process' found")
    
        if not bash_code_found:
            errors.append("[X] Bash code block with deployment commands not found")
        else:
            checks_passed.append("[C] Bash code block with deployment commands found")
    
        # ALL requirements met!
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: add-code-quality-report-to-code-examples-v2
# Description: Add Code Quality Report section to Code Examples Repository page
# =============================================================================
def _validate_agent_add_code_quality_report_to_code_examples(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate Code Quality Report with:
    - heading_2 '📊 Code Quality Report' after images but before code blocks
    - Yellow callout with ⚡ icon about coding standards
    - heading_3 '🔍 Code Analysis'
    - Numbered list with counts and analysis
    - Divider
    - Recommendation paragraph
    
    Returns 1.0 only if ALL requirements are met, otherwise 0.0
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Find Code Examples Repository page
    try:
        code_examples_pages = _get_pages_by_filter(backend, {"title": "Code Examples Repository"})
        if not code_examples_pages:
            code_examples_pages = _get_pages_by_filter(backend, {"title": "Code Examples"})
        if not code_examples_pages:
            errors.append("[X] Code Examples Repository page not found")
        else:
            checks_passed.append("[C] Code Examples Repository page found")
        code_examples_page = code_examples_pages[0]
    
        code_examples_id = code_examples_page.get("_id")
    
        # 2. Get blocks for page
        page_blocks = _get_blocks_by_filter(backend, {"pageId": code_examples_id})
    
        if len(page_blocks) < 5:
            errors.append(f"[X] Code Examples Repository page needs sufficient blocks, found {len(page_blocks)}")
        else:
            checks_passed.append(f"[C] Code Examples Repository page needs sufficient blocks, found {len(page_blocks)}")
    
        # 3. Find required structural elements
        h2_quality_report = False
        yellow_callout_found = False
        h3_analysis = False
        numbered_list_analysis = False
        divider_found = False
        recommendation_paragraph = False
    
        for block in page_blocks:
            block_type = block.get("type", "")
            block_content = block.get("content", "")
            block_properties = block.get("properties", {})
        
            # Check heading_2 Code Quality Report
            if block_type == "heading2" and "📊" in block_content and "code quality report" in block_content.lower():
                h2_quality_report = True
        
            # Check yellow callout
            if block_type == "callout":
                bg_color = block_properties.get("backgroundColor", "") if isinstance(block_properties, dict) else ""
                icon = block_properties.get("icon", "") if isinstance(block_properties, dict) else ""
                content_lower = block_content.lower()
            
                if "yellow" in bg_color.lower() and "⚡" in str(icon):
                    if "coding standards" in content_lower or "team coding standards" in content_lower:
                        yellow_callout_found = True
        
            # Check heading_3 Code Analysis
            if block_type == "heading3" and "🔍" in block_content and "code analysis" in block_content.lower():
                h3_analysis = True
        
            # Check numbered list with analysis
            if block_type == "numberedList":
                content_lower = block_content.lower()
                if "total code examples" in content_lower or "languages used" in content_lower or "syntax highlighting" in content_lower:
                    numbered_list_analysis = True
        
            # Check divider
            if block_type == "divider":
                divider_found = True
        
            # Check recommendation paragraph
            if block_type == "paragraph":
                content_lower = block_content.lower()
                if "recommendation" in content_lower and "syntax highlighting" in content_lower:
                    recommendation_paragraph = True
    
        # Validate all elements
        if not h2_quality_report:
            errors.append("[X] heading_2 '📊 Code Quality Report' not found")
        else:
            checks_passed.append("[C] heading_2 '📊 Code Quality Report' found")
    
        if not yellow_callout_found:
            errors.append("[X] Yellow callout with ⚡ icon about coding standards not found")
        else:
            checks_passed.append("[C] Yellow callout with ⚡ icon about coding standards found")
    
        if not h3_analysis:
            errors.append("[X] heading_3 '🔍 Code Analysis' not found")
        else:
            checks_passed.append("[C] heading_3 '🔍 Code Analysis' found")
    
        if not numbered_list_analysis:
            errors.append("[X] Numbered list with code analysis (total examples, languages, highlighting) not found")
        else:
            checks_passed.append("[C] Numbered list with code analysis (total examples, languages, highlighting) found")
    
        if not divider_found:
            errors.append("[X] Divider not found in Code Quality Report section")
        else:
            checks_passed.append("[C] Divider found in Code Quality Report section")
    
        if not recommendation_paragraph:
            errors.append("[X] Recommendation paragraph about syntax highlighting not found")
        else:
            checks_passed.append("[C] Recommendation paragraph about syntax highlighting found")
    
        # ALL requirements met!
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: create-team-performance-analytics-v2
# Description: Create Team Performance Analytics page under Team Directory
# with user activity metrics and contributor rankings
# =============================================================================
def _validate_agent_create_team_performance_analytics(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate Team Performance Analytics page with:
    - Page exists under 'Team Directory'
    - heading_1 '📊 Team Performance Analytics'
    - heading_2 '👥 Team Composition'
    - Purple callout with 🎯 icon about analytics
    - Paragraph with 'Total active team members: 6'
    - heading_2 '📈 Activity Metrics'
    - heading_3 '🏆 Most Active Contributors'
    - Numbered list of contributors ranked by page count
    - Divider
    - heading_3 '📅 Recent Activity' with recent pages count
    - Quote block with team productivity message
    
    Returns 1.0 only if ALL requirements are met, otherwise 0.0
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Find Team Directory page
    try:
        team_directory_pages = _get_pages_by_filter(backend, {"title": "Team Directory"})
        if not team_directory_pages:
            errors.append("[X] Team Directory page not found")
        else:
            checks_passed.append("[C] Team Directory page found")
        team_directory = team_directory_pages[0]
    
        team_directory_id = team_directory.get("_id")
    
        # 2. Find Team Performance Analytics page
        analytics_pages = _get_pages_by_filter(backend, {"title": "Team Performance Analytics"})
        if not analytics_pages:
            errors.append("[X] Team Performance Analytics page not found")
        else:
            checks_passed.append("[C] Team Performance Analytics page found")
        analytics_page = analytics_pages[0]
    
        analytics_page_id = analytics_page.get("_id")
    
        # 3. Verify analytics page is child of Team Directory
        is_child = _check_page_is_child_of(team_directory, analytics_page)
        if not is_child:
            errors.append("[X] Team Performance Analytics is not a child of Team Directory")
        else:
            checks_passed.append("[C] Team Performance Analytics is a child of Team Directory")
    
        # 4. Get blocks for analytics page
        page_blocks = _get_blocks_by_filter(backend, {"pageId": analytics_page_id})
    
        if len(page_blocks) < 8:
            errors.append(f"[X] Team Performance Analytics needs sufficient blocks, found {len(page_blocks)}")
        else:
            checks_passed.append(f"[C] Team Performance Analytics needs sufficient blocks, found {len(page_blocks)}")
    
        # 5. Find required elements
        h1_analytics = False
        h2_composition = False
        purple_callout = False
        team_members_paragraph = False
        h2_activity_metrics = False
        h3_contributors = False
        numbered_list_ranking = False
        divider_found = False
        h3_recent_activity = False
        recent_activity_paragraph = False
        quote_productivity = False
    
        for block in page_blocks:
            block_type = block.get("type", "")
            block_content = block.get("content", "")
            block_properties = block.get("properties", {})
            content_lower = block_content.lower()
        
            # heading_1 Team Performance Analytics
            if block_type == "heading1" and "📊" in block_content and "team performance analytics" in content_lower:
                h1_analytics = True
        
            # heading_2 Team Composition
            if block_type == "heading2" and "👥" in block_content and "team composition" in content_lower:
                h2_composition = True
        
            # Purple callout with 🎯
            if block_type == "callout":
                bg_color = block_properties.get("backgroundColor", "") if isinstance(block_properties, dict) else ""
                icon = block_properties.get("icon", "") if isinstance(block_properties, dict) else ""
            
                if "purple" in bg_color.lower() and "🎯" in str(icon):
                    if "analytics" in content_lower:
                        purple_callout = True
        
            # Team members paragraph
            if block_type == "paragraph" and "total active team members" in content_lower and "6" in block_content:
                team_members_paragraph = True
        
            # heading_2 Activity Metrics
            if block_type == "heading2" and "📈" in block_content and "activity metrics" in content_lower:
                h2_activity_metrics = True
        
            # heading_3 Most Active Contributors
            if block_type == "heading3" and "🏆" in block_content and "most active contributors" in content_lower:
                h3_contributors = True
        
            # Numbered list with rankings
            if block_type == "numberedList" and "user" in content_lower and "pages created" in content_lower:
                numbered_list_ranking = True
        
            # Divider
            if block_type == "divider":
                divider_found = True
        
            # heading_3 Recent Activity
            if block_type == "heading3" and "📅" in block_content and "recent activity" in content_lower:
                h3_recent_activity = True
        
            # Recent activity paragraph
            if block_type == "paragraph" and "pages updated" in content_lower and ("30 days" in content_lower or "last" in content_lower):
                recent_activity_paragraph = True
        
            # Quote about productivity
            if block_type == "quote" and "productivity" in content_lower and "collaboration" in content_lower:
                quote_productivity = True
    
        # Validate all elements
        if not h1_analytics:
            errors.append("[X] heading_1 '📊 Team Performance Analytics' not found")
        else:
            checks_passed.append("[C] heading_1 '📊 Team Performance Analytics' found")
    
        if not h2_composition:
            errors.append("[X] heading_2 '👥 Team Composition' not found")
        else:
            checks_passed.append("[C] heading_2 '👥 Team Composition' found")
    
        if not purple_callout:
            errors.append("[X] Purple callout with 🎯 icon about analytics not found")
        else:
            checks_passed.append("[C] Purple callout with 🎯 icon about analytics found")
    
        if not team_members_paragraph:
            errors.append("[X] Paragraph with 'Total active team members: 6' not found")
        else:
            checks_passed.append("[C] Paragraph with 'Total active team members: 6' found")
    
        if not h2_activity_metrics:
            errors.append("[X] heading_2 '📈 Activity Metrics' not found")
        else:
            checks_passed.append("[C] heading_2 '📈 Activity Metrics' found")
    
        if not h3_contributors:
            errors.append("[X] heading_3 '🏆 Most Active Contributors' not found")
        else:
            checks_passed.append("[C] heading_3 '🏆 Most Active Contributors' found")
    
        if not numbered_list_ranking:
            errors.append("[X] Numbered list with contributor rankings not found")
        else:
            checks_passed.append("[C] Numbered list with contributor rankings found")
    
        if not divider_found:
            errors.append("[X] Divider not found")
        else:
            checks_passed.append("[C] Divider found")
    
        if not h3_recent_activity:
            errors.append("[X] heading_3 '📅 Recent Activity' not found")
        else:
            checks_passed.append("[C] heading_3 '📅 Recent Activity' found")
    
        if not quote_productivity:
            errors.append("[X] Quote block about team productivity and collaboration not found")
        else:
            checks_passed.append("[C] Quote block about team productivity and collaboration found")
    
        # ALL requirements met!
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: add-sprint-blockers-to-standup-v2
# Description: Add Sprint Blockers section to Weekly Standup Template
# =============================================================================
def _validate_agent_add_sprint_blockers_to_standup(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate Sprint Blockers section with:
    - heading_2 '📆 Sprint Blockers - Week of January 15' after Blockers heading
    - 3 unchecked todos with specific emoji prefixes
    - Divider after todos
    - Yellow callout with ⚠️ icon about escalation
    
    Returns 1.0 only if ALL requirements are met, otherwise 0.0
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Find Weekly Standup Template page
    try:
        standup_pages = _get_pages_by_filter(backend, {"title": "Weekly Standup Template"})
        if not standup_pages:
            standup_pages = _get_pages_by_filter(backend, {"title": "Weekly Standup"})
        if not standup_pages:
            errors.append("[X] Weekly Standup Template page not found")
        else:
            checks_passed.append("[C] Weekly Standup Template page found")
        standup_page = standup_pages[0]
    
        standup_id = standup_page.get("_id")
    
        # 2. Get blocks for page
        page_blocks = _get_blocks_by_filter(backend, {"pageId": standup_id})
    
        if len(page_blocks) < 5:
            errors.append(f"[X] Weekly Standup Template page needs sufficient blocks, found {len(page_blocks)}")
        else:
            checks_passed.append(f"[C] Weekly Standup Template page needs sufficient blocks, found {len(page_blocks)}")
    
        # 3. Find required elements
        h2_sprint_blockers = False
        blockers_idx = -1
        sprint_blockers_idx = -1
    
        todo_backend_api = False
        todo_security_audit = False
        todo_data_migration = False
    
        divider_after_todos = False
        yellow_callout = False
    
        last_todo_idx = -1
        divider_idx = -1
    
        for idx, block in enumerate(page_blocks):
            block_type = block.get("type", "")
            block_content = block.get("content", "")
            block_properties = block.get("properties", {})
            content_lower = block_content.lower()
        
            # Find Blockers heading
            if block_type == "heading2" and "blockers" in content_lower and "sprint blockers" not in content_lower:
                blockers_idx = idx
        
            # Find Sprint Blockers heading
            if block_type == "heading2" and "📆" in block_content and "sprint blockers" in content_lower and "january 15" in content_lower:
                h2_sprint_blockers = True
                sprint_blockers_idx = idx
        
            # Find todos
            if block_type == "todo":
                checked = block_properties.get("checked", False) if isinstance(block_properties, dict) else False
            
                if not checked:
                    if "⏰" in block_content and "backend api" in content_lower and "infrastructure" in content_lower:
                        todo_backend_api = True
                        last_todo_idx = idx
                    if "🔒" in block_content and "security audit" in content_lower and "authentication" in content_lower:
                        todo_security_audit = True
                        last_todo_idx = idx
                    if "📊" in block_content and "data migration" in content_lower and "performance" in content_lower:
                        todo_data_migration = True
                        last_todo_idx = idx
        
            # Find divider
            if block_type == "divider":
                divider_idx = idx
        
            # Find yellow callout
            if block_type == "callout":
                bg_color = block_properties.get("backgroundColor", "") if isinstance(block_properties, dict) else ""
                icon = block_properties.get("icon", "") if isinstance(block_properties, dict) else ""
            
                if "yellow" in bg_color.lower() and "⚠️" in str(icon):
                    if "escalate" in content_lower and "3 days" in content_lower:
                        yellow_callout = True
    
        # Check divider is after todos
        if divider_idx > last_todo_idx and last_todo_idx != -1:
            divider_after_todos = True
    
        # Validate positioning
        if blockers_idx != -1 and sprint_blockers_idx != -1 and sprint_blockers_idx <= blockers_idx:
            errors.append("[X] Sprint Blockers section should appear after Blockers heading")
        else:
            checks_passed.append("[C] Sprint Blockers section should appear after Blockers heading")
    
        # Validate all elements
        if not h2_sprint_blockers:
            errors.append("[X] heading_2 '📆 Sprint Blockers - Week of January 15' not found")
        else:
            checks_passed.append("[C] heading_2 '📆 Sprint Blockers - Week of January 15' found")
    
        if not todo_backend_api:
            errors.append("[X] Unchecked todo with ⏰ about backend API deployment not found")
        else:
            checks_passed.append("[C] Unchecked todo with ⏰ about backend API deployment found")
    
        if not todo_security_audit:
            errors.append("[X] Unchecked todo with 🔒 about security audit not found")
        else:
            checks_passed.append("[C] Unchecked todo with 🔒 about security audit found")
    
        if not todo_data_migration:
            errors.append("[X] Unchecked todo with 📊 about data migration not found")
        else:
            checks_passed.append("[C] Unchecked todo with 📊 about data migration found")
    
        if not divider_after_todos:
            errors.append("[X] Divider not found after todos")
        else:
            checks_passed.append("[C] Divider found after todos")
    
        if not yellow_callout:
            errors.append("[X] Yellow callout with ⚠️ icon about escalating blockers not found")
        else:
            checks_passed.append("[C] Yellow callout with ⚠️ icon about escalating blockers found")
    
        # ALL requirements met!
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: reorganize-external-resources-by-domain-v2
# Description: Reorganize External Resources page by grouping bookmarks by domain
# =============================================================================
def _validate_agent_reorganize_external_resources_by_domain_2(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate External Resources reorganization with:
    - heading_2 sections for each domain with emoji prefixes
    - Bookmarks grouped correctly by domain
    - Blue callouts with resource counts per section
    - Summary paragraph at top with total count and today's date
    - Single dividers between sections
    
    Returns 1.0 only if ALL requirements are met, otherwise 0.0
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Find External Resources page
    try:
        resources_pages = _get_pages_by_filter(backend, {"title": "External Resources & Links"})
        if not resources_pages:
            resources_pages = _get_pages_by_filter(backend, {"title": "External Resources"})
        if not resources_pages:
            errors.append("[X] External Resources & Links page not found")
        else:
            checks_passed.append("[C] External Resources & Links page found")
        resources_page = resources_pages[0]
    
        resources_page_id = resources_page.get("_id")
    
        # 2. Get blocks for page
        page_blocks = _get_blocks_by_filter(backend, {"pageId": resources_page_id})
    
        if len(page_blocks) < 10:
            errors.append(f"[X] External Resources page needs sufficient blocks, found {len(page_blocks)}")
        else:
            checks_passed.append(f"[C] External Resources page needs sufficient blocks, found {len(page_blocks)}")
    
        # 3. Find required elements
        domain_sections = {
            "react": False,
            "typescript": False,
            "github": False,
            "mdn": False,
            "community": False
        }
    
        blue_callouts_count = 0
        summary_paragraph = False
        divider_count = 0
        bookmarks_found = 0
    
        for block in page_blocks:
            block_type = block.get("type", "")
            block_content = block.get("content", "")
            block_properties = block.get("properties", {})
            content_lower = block_content.lower()
        
            # Check for domain section headings
            if block_type == "heading2":
                if "🌐" in block_content and "react" in content_lower:
                    domain_sections["react"] = True
                if "📘" in block_content and "typescript" in content_lower:
                    domain_sections["typescript"] = True
                if "🔧" in block_content and "github" in content_lower:
                    domain_sections["github"] = True
                if "📚" in block_content and "mdn" in content_lower:
                    domain_sections["mdn"] = True
                if "💬" in block_content and "community" in content_lower:
                    domain_sections["community"] = True
        
            # Count blue callouts with resource counts
            if block_type == "callout":
                bg_color = block_properties.get("backgroundColor", "") if isinstance(block_properties, dict) else ""
                if "blue" in bg_color.lower() and "resources in this section" in content_lower:
                    blue_callouts_count += 1
        
            # Check summary paragraph
            if block_type == "paragraph" and "total resources" in content_lower and "domains" in content_lower:
                summary_paragraph = True
        
            # Count dividers
            if block_type == "divider":
                divider_count += 1
        
            # Count bookmarks
            if block_type == "bookmark":
                bookmarks_found += 1
    
        # Validate domain sections
        missing_sections = [domain for domain, found in domain_sections.items() if not found]
        if missing_sections:
            errors.append(f"[X] Missing domain sections: {', '.join(missing_sections)}")
        else:
            checks_passed.append(f"[C] has domain sections: {', '.join(missing_sections)}")
    
        if blue_callouts_count < 5:
            errors.append(f"[X] Expected at least 5 blue callouts with resource counts, found {blue_callouts_count}")
        else:
            checks_passed.append(f"[C] Found at least 5 blue callouts with resource counts ({blue_callouts_count})")
    
        if not summary_paragraph:
            errors.append("[X] Summary paragraph with total resources count not found")
        else:
            checks_passed.append("[C] Summary paragraph with total resources count found")
    
        if divider_count < 4:
            errors.append(f"[X] Expected at least 4 dividers between sections, found {divider_count}")
        else:
            checks_passed.append(f"[C] Found at least 4 dividers between sections ({divider_count})")
    
        if bookmarks_found < 3:
            errors.append(f"[X] Expected bookmarks to be present, found {bookmarks_found}")
        else:
            checks_passed.append(f"[C] Expected bookmarks to be present, found {bookmarks_found}")
    
        # ALL requirements met!
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: add-complex-update-to-standup-v2
# Description: Complex update to Weekly Standup Template with multiple sections
# =============================================================================
def _validate_agent_add_complex_update_to_standup(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate complex standup update with:
    - New week section after Blockers with next Monday's date
    - heading_3 'Sprint Goals' with 3 unchecked todos
    - heading_3 'Team Capacity' with blue callout
    - Bookmark to Jira after 'What I did this week'
    - First todo under 'What I plan to do next week' is checked
    - Quote block at the end
    
    Returns 1.0 only if ALL requirements are met, otherwise 0.0
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Find Weekly Standup Template page
    try:
        standup_pages = _get_pages_by_filter(backend, {"title": "Weekly Standup Template"})
        if not standup_pages:
            standup_pages = _get_pages_by_filter(backend, {"title": "Weekly Standup"})
        if not standup_pages:
            errors.append("[X] Weekly Standup Template page not found")
        else:
            checks_passed.append("[C] Weekly Standup Template page found")
        standup_page = standup_pages[0]
    
        standup_id = standup_page.get("_id")
    
        # 2. Get blocks for page
        page_blocks = _get_blocks_by_filter(backend, {"pageId": standup_id})
    
        if len(page_blocks) < 8:
            errors.append(f"[X] Weekly Standup Template page needs sufficient blocks, found {len(page_blocks)}")
        else:
            checks_passed.append(f"[C] Weekly Standup Template page needs sufficient blocks, found {len(page_blocks)}")
    
        # 3. Find required elements
        h2_week_of = False
        h3_sprint_goals = False
        sprint_goal_todos = 0
        h3_team_capacity = False
        blue_callout_capacity = False
        jira_bookmark = False
        quote_progress = False
    
        for block in page_blocks:
            block_type = block.get("type", "")
            block_content = block.get("content", "")
            block_properties = block.get("properties", {})
            content_lower = block_content.lower()
        
            # Check for week section
            if block_type == "heading2" and "week of" in content_lower:
                h2_week_of = True
        
            # Check for Sprint Goals heading
            if block_type == "heading3" and "sprint goals" in content_lower:
                h3_sprint_goals = True
        
            # Count sprint goal todos
            if block_type == "todo":
                if "🎯" in block_content and "authentication" in content_lower:
                    sprint_goal_todos += 1
                elif "🔧" in block_content and "database" in content_lower:
                    sprint_goal_todos += 1
                elif "📚" in block_content and "api documentation" in content_lower:
                    sprint_goal_todos += 1
        
            # Check Team Capacity heading
            if block_type == "heading3" and "team capacity" in content_lower:
                h3_team_capacity = True
        
            # Check blue callout for capacity
            if block_type == "callout":
                bg_color = block_properties.get("backgroundColor", "") if isinstance(block_properties, dict) else ""
                icon = block_properties.get("icon", "") if isinstance(block_properties, dict) else ""
            
                if "blue" in bg_color.lower() and "👥" in str(icon):
                    if "team available" in content_lower or "no planned absences" in content_lower:
                        blue_callout_capacity = True
        
            # Check Jira bookmark
            if block_type == "bookmark":
                url = block_properties.get("url", "") if isinstance(block_properties, dict) else ""
                if "jira" in url.lower() or "jira" in content_lower:
                    jira_bookmark = True
        
            # Check quote about progress
            if block_type == "quote" and "progress" in content_lower:
                quote_progress = True
    
        # Validate all elements
        if not h2_week_of:
            errors.append("[X] heading_2 with 'Week of [date]' not found")
        else:
            checks_passed.append("[C] heading_2 with 'Week of [date]' found")
    
        if not h3_sprint_goals:
            errors.append("[X] heading_3 'Sprint Goals' not found")
        else:
            checks_passed.append("[C] heading_3 'Sprint Goals' found")
    
        if sprint_goal_todos < 3:
            errors.append(f"[X] Expected 3 sprint goal todos, found {sprint_goal_todos}")
        else:
            checks_passed.append(f"[C] Found 3 sprint goal todos as expected")
    
        if not h3_team_capacity:
            errors.append("[X] heading_3 'Team Capacity' not found")
        else:
            checks_passed.append("[C] heading_3 'Team Capacity' found")
    
        if not blue_callout_capacity:
            errors.append("[X] Blue callout with 👥 icon about team availability not found")
        else:
            checks_passed.append("[C] Blue callout with 👥 icon about team availability found")
    
        if not jira_bookmark:
            errors.append("[X] Bookmark to Jira not found")
        else:
            checks_passed.append("[C] Bookmark to Jira found")
    
        if not quote_progress:
            errors.append("[X] Quote block about progress not found at end")
        else:
            checks_passed.append("[C] Quote block about progress found at end")
    
        # ALL requirements met!
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: create-code-examples-summary-v2
# Description: Create Code Examples Summary analyzing code blocks
# =============================================================================
def _validate_agent_create_code_examples_summary(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate Code Examples Summary with:
    - Page exists as child of Code Examples Repository
    - heading_1 '📖 Code Examples Summary'
    - heading_2 '🔍 Code Examples Overview' with paragraph about counts
    - Language sections with correct emojis
    - heading_2 '📈 Language Distribution' with bulleted list
    - Bookmark to parent page
    
    Returns 1.0 only if ALL requirements are met, otherwise 0.0
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Find Code Examples Repository page
    try:
        code_examples_pages = _get_pages_by_filter(backend, {"title": "Code Examples Repository"})
        if not code_examples_pages:
            errors.append("[X] Code Examples Repository page not found")
        else:
            checks_passed.append("[C] Code Examples Repository page found")
        code_examples_page = code_examples_pages[0]
    
        # 2. Find Code Examples Summary page
        summary_pages = _get_pages_by_filter(backend, {"title": "Code Examples Summary"})
        if not summary_pages:
            errors.append("[X] Code Examples Summary page not found")
        else:
            checks_passed.append("[C] Code Examples Summary page found")
        summary_page = summary_pages[0]
    
        summary_page_id = summary_page.get("_id")
    
        # 3. Verify summary is child of Code Examples Repository
        is_child = _check_page_is_child_of(code_examples_page, summary_page)
        if not is_child:
            errors.append("[X] Code Examples Summary is not a child of Code Examples Repository")
        else:
            checks_passed.append("[C] Code Examples Summary is a child of Code Examples Repository")
    
        # 4. Get blocks for summary page
        page_blocks = _get_blocks_by_filter(backend, {"pageId": summary_page_id})
    
        if len(page_blocks) < 6:
            errors.append(f"[X] Code Examples Summary needs sufficient blocks, found {len(page_blocks)}")
        else:
            checks_passed.append(f"[C] Code Examples Summary needs sufficient blocks, found {len(page_blocks)}")
    
        # 5. Find required elements
        h1_summary = False
        h2_overview = False
        overview_paragraph = False
        h2_distribution = False
        bulleted_distribution = False
        bookmark_parent = False
    
        language_sections = {
            "javascript": False,
            "python": False,
            "typescript": False,
            "bash": False,
            "sql": False
        }
    
        for block in page_blocks:
            block_type = block.get("type", "")
            block_content = block.get("content", "")
            block_properties = block.get("properties", {})
            content_lower = block_content.lower()
        
            # heading_1 Code Examples Summary
            if block_type == "heading1" and "📖" in block_content and "code examples summary" in content_lower:
                h1_summary = True
        
            # heading_2 Code Examples Overview
            if block_type == "heading2" and "🔍" in block_content and "code examples overview" in content_lower:
                h2_overview = True
        
            # Overview paragraph with counts
            if block_type == "paragraph" and "total code examples" in content_lower and "languages" in content_lower:
                overview_paragraph = True
        
            # Language section headings
            if block_type == "heading3":
                if "🟨" in block_content and "javascript" in content_lower:
                    language_sections["javascript"] = True
                if "🐍" in block_content and "python" in content_lower:
                    language_sections["python"] = True
                if "🔷" in block_content and "typescript" in content_lower:
                    language_sections["typescript"] = True
                if "🐧" in block_content and "bash" in content_lower:
                    language_sections["bash"] = True
                if "🗄️" in block_content and "sql" in content_lower:
                    language_sections["sql"] = True
        
            # heading_2 Language Distribution
            if block_type == "heading2" and "📈" in block_content and "language distribution" in content_lower:
                h2_distribution = True
        
            # Bulleted list for distribution
            if block_type == "bulletedList" and ("javascript" in content_lower or "python" in content_lower):
                bulleted_distribution = True
        
            # Bookmark to parent
            if block_type == "bookmark":
                caption = block_properties.get("caption", "") if isinstance(block_properties, dict) else ""
                if "full code examples" in caption.lower() or "view full" in caption.lower():
                    bookmark_parent = True
    
        # Validate all elements
        if not h1_summary:
            errors.append("[X] heading_1 '📖 Code Examples Summary' not found")
        else:
            checks_passed.append("[C] heading_1 '📖 Code Examples Summary' found")
    
        if not h2_overview:
            errors.append("[X] heading_2 '🔍 Code Examples Overview' not found")
        else:
            checks_passed.append("[C] heading_2 '🔍 Code Examples Overview' found")
    
        if not overview_paragraph:
            errors.append("[X] Overview paragraph with code example counts not found")
        else:
            checks_passed.append("[C] Overview paragraph with code example counts found")
    
        # Check at least some language sections exist
        found_langs = [lang for lang, found in language_sections.items() if found]
        if len(found_langs) < 2:
            errors.append(f"[X] Expected language section headings with correct emojis, found: {found_langs}")
        else:
            checks_passed.append(f"[C] Expected language section headings with correct emojis, found: {found_langs}")
    
        if not h2_distribution:
            errors.append("[X] heading_2 '📈 Language Distribution' not found")
        else:
            checks_passed.append("[C] heading_2 '📈 Language Distribution' found")
    
        if not bulleted_distribution:
            errors.append("[X] Bulleted list with language distribution not found")
        else:
            checks_passed.append("[C] Bulleted list with language distribution found")
    
        if not bookmark_parent:
            errors.append("[X] Bookmark to parent page not found")
        else:
            checks_passed.append("[C] Bookmark to parent page found")
    
        # ALL requirements met!
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: create-sprint-planning-archive-v2
# Description: Create Sprint Planning Archive under Meeting Notes
# =============================================================================
def _validate_agent_create_sprint_planning_archive(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate Sprint Planning Archive with:
    - Page exists under Meeting Notes
    - heading_1 '📚 Sprint Planning Archive'
    - heading_2 '📅 January 2024 Sprints'
    - Mirrored structure from original sprint planning
    - Orange callout with ⚠️ icon about archive
    - Bookmark to original Sprint Planning page
    
    Returns 1.0 only if ALL requirements are met, otherwise 0.0
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Find Meeting Notes page
    try:
        meeting_notes_pages = _get_pages_by_filter(backend, {"title": "Meeting Notes"})
        if not meeting_notes_pages:
            errors.append("[X] Meeting Notes page not found")
        else:
            checks_passed.append("[C] Meeting Notes page found")
        meeting_notes = meeting_notes_pages[0]
    
        # 2. Find Sprint Planning Archive page
        archive_pages = _get_pages_by_filter(backend, {"title": "Sprint Planning Archive"})
        if not archive_pages:
            errors.append("[X] Sprint Planning Archive page not found")
        else:
            checks_passed.append("[C] Sprint Planning Archive page found")
        archive_page = archive_pages[0]
    
        archive_page_id = archive_page.get("_id")
    
        # 3. Verify archive is child of Meeting Notes
        is_child = _check_page_is_child_of(meeting_notes, archive_page)
        if not is_child:
            errors.append("[X] Sprint Planning Archive is not a child of Meeting Notes")
        else:
            checks_passed.append("[C] Sprint Planning Archive is a child of Meeting Notes")
    
        # 4. Get blocks for archive page
        page_blocks = _get_blocks_by_filter(backend, {"pageId": archive_page_id})
    
        if len(page_blocks) < 5:
            errors.append(f"[X] Sprint Planning Archive needs sufficient blocks, found {len(page_blocks)}")
        else:
            checks_passed.append(f"[C] Sprint Planning Archive needs sufficient blocks, found {len(page_blocks)}")
    
        # 5. Find required elements
        h1_archive = False
        h2_january = False
        has_summary_paragraph = False
        orange_callout = False
        bookmark_original = False
    
        for block in page_blocks:
            block_type = block.get("type", "")
            block_content = block.get("content", "")
            block_properties = block.get("properties", {})
            content_lower = block_content.lower()
        
            # heading_1 Sprint Planning Archive
            if block_type == "heading1" and "📚" in block_content and "sprint planning archive" in content_lower:
                h1_archive = True
        
            # heading_2 January 2024 Sprints
            if block_type == "heading2" and "📅" in block_content and "january" in content_lower and "2024" in content_lower:
                h2_january = True
        
            # Summary paragraph with task counts
            if block_type == "paragraph" and ("assigned tasks" in content_lower or "team members" in content_lower):
                has_summary_paragraph = True
        
            # Orange callout about archive
            if block_type == "callout":
                bg_color = block_properties.get("backgroundColor", "") if isinstance(block_properties, dict) else ""
                icon = block_properties.get("icon", "") if isinstance(block_properties, dict) else ""
            
                if "orange" in bg_color.lower() and "⚠️" in str(icon):
                    if "archived" in content_lower or "snapshot" in content_lower:
                        orange_callout = True
        
            # Bookmark to original
            if block_type == "bookmark":
                if "sprint planning" in content_lower:
                    bookmark_original = True
    
        # Validate all elements
        if not h1_archive:
            errors.append("[X] heading_1 '📚 Sprint Planning Archive' not found")
        else:
            checks_passed.append("[C] heading_1 '📚 Sprint Planning Archive' found")
    
        if not h2_january:
            errors.append("[X] heading_2 '📅 January 2024 Sprints' not found")
        else:
            checks_passed.append("[C] heading_2 '📅 January 2024 Sprints' found")
    
        if not has_summary_paragraph:
            errors.append("[X] Summary paragraph with task counts not found")
        else:
            checks_passed.append("[C] Summary paragraph with task counts found")
    
        if not orange_callout:
            errors.append("[X] Orange callout with ⚠️ icon about archive not found")
        else:
            checks_passed.append("[C] Orange callout with ⚠️ icon about archive found")
    
        if not bookmark_original:
            errors.append("[X] Bookmark to original Sprint Planning page not found")
        else:
            checks_passed.append("[C] Bookmark to original Sprint Planning page found")
    
        # ALL requirements met!
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: create-meeting-analytics-dashboard-v2
# Description: Create Meeting Analytics Dashboard analyzing child pages
# =============================================================================
def _validate_agent_create_meeting_analytics_dashboard(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate Meeting Analytics Dashboard with:
    - Page exists under Meeting Notes
    - heading_1 '📊 Meeting Analytics Dashboard'
    - heading_2 '📅 Meeting Summary' with count paragraph
    - heading_2 '✅ Action Items Tracker'
    - Sections for each meeting with todos
    - Status prefixes (✓ for checked, ○ for unchecked)
    
    Returns 1.0 only if ALL requirements are met, otherwise 0.0
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Find Meeting Notes page
    try:
        meeting_notes_pages = _get_pages_by_filter(backend, {"title": "Meeting Notes"})
        if not meeting_notes_pages:
            errors.append("[X] Meeting Notes page not found")
        else:
            checks_passed.append("[C] Meeting Notes page found")
        meeting_notes = meeting_notes_pages[0]
    
        # 2. Find Meeting Analytics Dashboard page
        dashboard_pages = _get_pages_by_filter(backend, {"title": "Meeting Analytics Dashboard"})
        if not dashboard_pages:
            errors.append("[X] Meeting Analytics Dashboard page not found")
        else:
            checks_passed.append("[C] Meeting Analytics Dashboard page found")
        dashboard_page = dashboard_pages[0]
    
        dashboard_page_id = dashboard_page.get("_id")
    
        # 3. Verify dashboard is child of Meeting Notes
        is_child = _check_page_is_child_of(meeting_notes, dashboard_page)
        if not is_child:
            errors.append("[X] Meeting Analytics Dashboard is not a child of Meeting Notes")
        else:
            checks_passed.append("[C] Meeting Analytics Dashboard is a child of Meeting Notes")
    
        # 4. Get blocks for dashboard page
        page_blocks = _get_blocks_by_filter(backend, {"pageId": dashboard_page_id})
    
        if len(page_blocks) < 5:
            errors.append(f"[X] Meeting Analytics Dashboard needs sufficient blocks, found {len(page_blocks)}")
        else:
            checks_passed.append(f"[C] Meeting Analytics Dashboard needs sufficient blocks, found {len(page_blocks)}")
    
        # 5. Find required elements
        h1_dashboard = False
        h2_meeting_summary = False
        meeting_count_paragraph = False
        h2_action_items = False
        meeting_sections = 0
        has_status_prefixes = False
    
        for block in page_blocks:
            block_type = block.get("type", "")
            block_content = block.get("content", "")
            content_lower = block_content.lower()
        
            # heading_1 Meeting Analytics Dashboard
            if block_type == "heading1" and "📊" in block_content and "meeting analytics dashboard" in content_lower:
                h1_dashboard = True
        
            # heading_2 Meeting Summary
            if block_type == "heading2" and "📅" in block_content and "meeting summary" in content_lower:
                h2_meeting_summary = True
        
            # Meeting count paragraph
            if block_type == "paragraph" and "total meetings documented" in content_lower:
                meeting_count_paragraph = True
        
            # heading_2 Action Items Tracker
            if block_type == "heading2" and "✅" in block_content and "action items" in content_lower:
                h2_action_items = True
        
            # Meeting sections (heading_3 with meeting title)
            if block_type == "heading3" and "📝" in block_content:
                meeting_sections += 1
        
            # Check for status prefixes in numbered list
            if block_type == "numberedList":
                if "✓" in block_content or "○" in block_content:
                    has_status_prefixes = True
    
        # Validate all elements
        if not h1_dashboard:
            errors.append("[X] heading_1 '📊 Meeting Analytics Dashboard' not found")
        else:
            checks_passed.append("[C] heading_1 '📊 Meeting Analytics Dashboard' found")
    
        if not h2_meeting_summary:
            errors.append("[X] heading_2 '📅 Meeting Summary' not found")
        else:
            checks_passed.append("[C] heading_2 '📅 Meeting Summary' found")
    
        if not meeting_count_paragraph:
            errors.append("[X] Paragraph with 'Total meetings documented' count not found")
        else:
            checks_passed.append("[C] Paragraph with 'Total meetings documented' count found")
    
        if not h2_action_items:
            errors.append("[X] heading_2 '✅ Action Items Tracker' not found")
        else:
            checks_passed.append("[C] heading_2 '✅ Action Items Tracker' found")
    
        if meeting_sections < 1:
            errors.append("[X] No meeting sections with 📝 prefix found")
        else:
            checks_passed.append("[C] meeting sections with 📝 prefix found")
    
        if not has_status_prefixes:
            errors.append("[X] Status prefixes (✓ for checked, ○ for unchecked) not found in numbered lists")
        else:
            checks_passed.append("[C] Status prefixes (✓ for checked, ○ for unchecked) found in numbered lists")
    
        # ALL requirements met!
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: add-priority-matrix-to-feature-requests-v2
# Description: Add Priority Matrix section to Feature Requests page
# =============================================================================
def _validate_agent_add_priority_matrix_to_feature_requests(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate Priority Matrix with:
    - heading_2 '🎯 Priority Matrix' at beginning
    - 4 quadrant headings with corresponding callouts
    - Green callout for high impact/low effort
    - Blue callout for high impact/high effort
    - Yellow callout for low impact/low effort
    - Gray callout for low impact/high effort (no icon)
    - Divider at end
    
    Returns 1.0 only if ALL requirements are met, otherwise 0.0
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Find Feature Requests page
    try:
        feature_requests_pages = _get_pages_by_filter(backend, {"title": "Feature Requests"})
        if not feature_requests_pages:
            errors.append("[X] Feature Requests page not found")
        else:
            checks_passed.append("[C] Feature Requests page found")
        feature_requests = feature_requests_pages[0]
    
        feature_requests_id = feature_requests.get("_id")
    
        # 2. Get blocks for page
        page_blocks = _get_blocks_by_filter(backend, {"pageId": feature_requests_id})
    
        if len(page_blocks) < 9:
            errors.append(f"[X] Feature Requests page needs sufficient blocks, found {len(page_blocks)}")
        else:
            checks_passed.append(f"[C] Feature Requests page needs sufficient blocks, found {len(page_blocks)}")
    
        # 3. Find required elements
        h2_priority_matrix = False
        priority_matrix_idx = -1
    
        quadrants = {
            "high_impact_low_effort": {"heading": False, "callout": False},
            "high_impact_high_effort": {"heading": False, "callout": False},
            "low_impact_low_effort": {"heading": False, "callout": False},
            "low_impact_high_effort": {"heading": False, "callout": False}
        }
    
        divider_at_end = False
        last_block_type = ""
    
        for idx, block in enumerate(page_blocks):
            block_type = block.get("type", "")
            block_content = block.get("content", "")
            block_properties = block.get("properties", {})
            content_lower = block_content.lower()
        
            last_block_type = block_type
        
            # heading_2 Priority Matrix
            if block_type == "heading2" and "🎯" in block_content and "priority matrix" in content_lower:
                h2_priority_matrix = True
                priority_matrix_idx = idx
        
            # Quadrant headings
            if block_type == "heading3":
                if "🚀" in block_content and "high impact" in content_lower and "low effort" in content_lower:
                    quadrants["high_impact_low_effort"]["heading"] = True
                if "⭐" in block_content and "high impact" in content_lower and "high effort" in content_lower:
                    quadrants["high_impact_high_effort"]["heading"] = True
                if "🔄" in block_content and "low impact" in content_lower and "low effort" in content_lower:
                    quadrants["low_impact_low_effort"]["heading"] = True
                if "❌" in block_content and "low impact" in content_lower and "high effort" in content_lower:
                    quadrants["low_impact_high_effort"]["heading"] = True
        
            # Callouts for quadrants
            if block_type == "callout":
                bg_color = block_properties.get("backgroundColor", "") if isinstance(block_properties, dict) else ""
                icon = block_properties.get("icon", "") if isinstance(block_properties, dict) else ""
            
                if "green" in bg_color.lower() and "✅" in str(icon):
                    if "dark mode" in content_lower or "keyboard shortcuts" in content_lower:
                        quadrants["high_impact_low_effort"]["callout"] = True
            
                if "blue" in bg_color.lower() and "🎯" in str(icon):
                    if "real-time collaboration" in content_lower or "mobile app" in content_lower:
                        quadrants["high_impact_high_effort"]["callout"] = True
            
                if "yellow" in bg_color.lower() and "💭" in str(icon):
                    if "custom emojis" in content_lower or "sound notifications" in content_lower:
                        quadrants["low_impact_low_effort"]["callout"] = True
            
                if "gray" in bg_color.lower():
                    if "custom themes" in content_lower or "advanced animations" in content_lower:
                        quadrants["low_impact_high_effort"]["callout"] = True
        
            # Divider
            if block_type == "divider":
                divider_at_end = True
    
        # Validate priority matrix is at beginning
        if not h2_priority_matrix:
            errors.append("[X] heading_2 '🎯 Priority Matrix' not found")
        else:
            checks_passed.append("[C] heading_2 '🎯 Priority Matrix' found")
    
        if priority_matrix_idx > 2:
            errors.append("[X] Priority Matrix should appear at the beginning of the page")
        else:
            checks_passed.append("[C] Priority Matrix should appear at the beginning of the page")
    
        # Validate all quadrants
        for quadrant_name, checks in quadrants.items():
            if not checks["heading"]:
                errors.append(f"[X] Heading for {quadrant_name.replace('_', ' ')} quadrant not found")
            else:
                checks_passed.append(f"[C] Heading for {quadrant_name.replace('_', ' ')} quadrant found")
            if not checks["callout"]:
                errors.append(f"[X] Callout for {quadrant_name.replace('_', ' ')} quadrant not found")
            else:
                checks_passed.append(f"[C] Callout for {quadrant_name.replace('_', ' ')} quadrant found")
    
        if not divider_at_end:
            errors.append("[X] Divider not found at end of Priority Matrix")
        else:
            checks_passed.append("[C] Divider found at end of Priority Matrix")
    
        # ALL requirements met!
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: add-document-index-to-architecture-v2
# Description: Add document index and move State Management page
# =============================================================================
def _validate_agent_add_document_index_to_architecture(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate Architecture document index with:
    - Gray callout with 🗂️ icon showing child count
    - heading_2 '📑 Document Index'
    - Numbered list of child page titles with icons
    - Divider
    - heading_2 '🔄 Last Updated' with most recent date
    - State Management page moved to be direct child of Project Documentation
    
    Returns 1.0 only if ALL requirements are met, otherwise 0.0
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Find Architecture page
    try:
        architecture_pages = _get_pages_by_filter(backend, {"title": "Architecture"})
        if not architecture_pages:
            errors.append("[X] Architecture page not found")
        else:
            checks_passed.append("[C] Architecture page found")
        architecture_page = architecture_pages[0]
    
        architecture_id = architecture_page.get("_id")
    
        # 2. Find Project Documentation page
        project_docs_pages = _get_pages_by_filter(backend, {"title": "Project Documentation"})
        if not project_docs_pages:
            errors.append("[X] Project Documentation page not found")
        else:
            checks_passed.append("[C] Project Documentation page found")
        project_docs = project_docs_pages[0]
    
        # 3. Find State Management page
        state_management_pages = _get_pages_by_filter(backend, {"title": "State Management"})
        if not state_management_pages:
            errors.append("[X] State Management page not found")
        else:
            checks_passed.append("[C] State Management page found")
        state_management = state_management_pages[0]
    
        # 4. Verify State Management is child of Project Documentation (not Architecture)
        is_child_of_project_docs = _check_page_is_child_of(project_docs, state_management)
        if not is_child_of_project_docs:
            errors.append("[X] State Management page should be moved to be direct child of Project Documentation")
        else:
            checks_passed.append("[C] State Management page should be moved to be direct child of Project Documentation")
    
        # 5. Get blocks for Architecture page
        page_blocks = _get_blocks_by_filter(backend, {"pageId": architecture_id})
    
        if len(page_blocks) < 5:
            errors.append(f"[X] Architecture page needs sufficient blocks, found {len(page_blocks)}")
        else:
            checks_passed.append(f"[C] Architecture page needs sufficient blocks, found {len(page_blocks)}")
    
        # 6. Find required elements
        gray_callout_count = False
        h2_document_index = False
        numbered_list_titles = False
        divider_found = False
        h2_last_updated = False
        last_updated_paragraph = False
    
        for block in page_blocks:
            block_type = block.get("type", "")
            block_content = block.get("content", "")
            block_properties = block.get("properties", {})
            content_lower = block_content.lower()
        
            # Gray callout with count
            if block_type == "callout":
                bg_color = block_properties.get("backgroundColor", "") if isinstance(block_properties, dict) else ""
                icon = block_properties.get("icon", "") if isinstance(block_properties, dict) else ""
            
                if "gray" in bg_color.lower() and "🗂️" in str(icon):
                    if "architecture documents" in content_lower or "contains" in content_lower:
                        gray_callout_count = True
        
            # heading_2 Document Index
            if block_type == "heading2" and "📑" in block_content and "document index" in content_lower:
                h2_document_index = True
        
            # Numbered list with page titles
            if block_type == "numberedList":
                numbered_list_titles = True
        
            # Divider
            if block_type == "divider":
                divider_found = True
        
            # heading_2 Last Updated
            if block_type == "heading2" and "🔄" in block_content and "last updated" in content_lower:
                h2_last_updated = True
        
            # Last updated paragraph
            if block_type == "paragraph" and "most recent update" in content_lower:
                last_updated_paragraph = True
    
        # Validate all elements
        if not gray_callout_count:
            errors.append("[X] Gray callout with 🗂️ icon showing document count not found")
        else:
            checks_passed.append("[C] Gray callout with 🗂️ icon showing document count found")
    
        if not h2_document_index:
            errors.append("[X] heading_2 '📑 Document Index' not found")
        else:
            checks_passed.append("[C] heading_2 '📑 Document Index' found")
    
        if not numbered_list_titles:
            errors.append("[X] Numbered list of child page titles not found")
        else:
            checks_passed.append("[C] Numbered list of child page titles found")
    
        if not divider_found:
            errors.append("[X] Divider not found")
        else:
            checks_passed.append("[C] Divider found")
    
        if not h2_last_updated:
            errors.append("[X] heading_2 '🔄 Last Updated' not found")
        else:
            checks_passed.append("[C] heading_2 '🔄 Last Updated' found")
    
        if not last_updated_paragraph:
            errors.append("[X] Paragraph with most recent update date not found")
        else:
            checks_passed.append("[C] Paragraph with most recent update date found")
    
        # ALL requirements met!
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: add-performance-requirements-to-prd-v2
# Description: Add Performance Requirements subsection to PRD
# =============================================================================
def _validate_agent_add_performance_requirements_to_prd(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate Performance Requirements with:
    - heading_3 '⚡ Performance Requirements' between Tech Req Part 1 and Part 2
    - Orange callout with ⚠️ icon about API response times
    - Numbered list with 4 performance metrics
    - Validation paragraph about staging
    
    Returns 1.0 only if ALL requirements are met, otherwise 0.0
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Find PRD page
    try:
        prd_pages = _get_pages_by_filter(backend, {"title": "Product Requirements Document"})
        if not prd_pages:
            prd_pages = _get_pages_by_filter(backend, {"title": "Comprehensive Product Requirements Document"})
        if not prd_pages:
            prd_pages = _get_pages_by_filter(backend, {"title": "PRD"})
        if not prd_pages:
            errors.append("[X] Product Requirements Document page not found")
        else:
            checks_passed.append("[C] Product Requirements Document page found")
        prd_page = prd_pages[0]
    
        prd_id = prd_page.get("_id")
    
        # 2. Get blocks for page
        page_blocks = _get_blocks_by_filter(backend, {"pageId": prd_id})
    
        if len(page_blocks) < 5:
            errors.append(f"[X] PRD page needs sufficient blocks, found {len(page_blocks)}")
        else:
            checks_passed.append(f"[C] PRD page needs sufficient blocks, found {len(page_blocks)}")
    
        # 3. Find required elements
        h3_performance = False
        orange_callout = False
        numbered_list_metrics = False
        validation_paragraph = False
    
        # Track positions for ordering validation
        tech_req_part1_idx = -1
        tech_req_part2_idx = -1
        performance_idx = -1
    
        # Track metrics found across all numbered list blocks (each metric is in its own block)
        found_page_load = False
        found_database_queries = False
        found_search_latency = False
        found_concurrent_users = False
    
        for idx, block in enumerate(page_blocks):
            block_type = block.get("type", "")
            block_content = block.get("content", "")
            block_properties = block.get("properties", {})
            content_lower = block_content.lower()
        
            # Find Technical Requirements Part 1 and Part 2 positions
            if "technical requirements" in content_lower:
                if "part 1" in content_lower:
                    tech_req_part1_idx = idx
                elif "part 2" in content_lower:
                    tech_req_part2_idx = idx
        
            # heading_3 Performance Requirements
            if block_type == "heading3" and "⚡" in block_content and "performance requirements" in content_lower:
                h3_performance = True
                performance_idx = idx
        
            # Orange callout about API response
            if block_type == "callout":
                bg_color = block_properties.get("backgroundColor", "") if isinstance(block_properties, dict) else ""
                icon = block_properties.get("icon", "") if isinstance(block_properties, dict) else ""
            
                if "orange" in bg_color.lower() and "⚠️" in str(icon):
                    if "api" in content_lower and "200ms" in content_lower:
                        orange_callout = True
        
            # Numbered list with metrics - each metric is in its own block
            if block_type == "numberedList":
                if "page load time" in content_lower or "<2 seconds" in content_lower:
                    found_page_load = True
                if "database queries" in content_lower or "<50ms" in content_lower:
                    found_database_queries = True
                if "search latency" in content_lower or "<100ms" in content_lower:
                    found_search_latency = True
                if "concurrent users" in content_lower or "10,000" in content_lower:
                    found_concurrent_users = True
        
            # Validation paragraph
            if block_type == "paragraph" and "performance benchmarks" in content_lower and "staging" in content_lower:
                validation_paragraph = True
    
        # Check if at least 4 unique metrics were found across all numbered list blocks
        metrics_count = sum([found_page_load, found_database_queries, found_search_latency, found_concurrent_users])
        if metrics_count >= 4:
            numbered_list_metrics = True
    
        # Validate all elements
        if not h3_performance:
            errors.append("[X] heading_3 '⚡ Performance Requirements' not found")
        else:
            checks_passed.append("[C] heading_3 '⚡ Performance Requirements' found")
    
        if not orange_callout:
            errors.append("[X] Orange callout with ⚠️ icon about API response times not found")
        else:
            checks_passed.append("[C] Orange callout with ⚠️ icon about API response times found")
    
        if not numbered_list_metrics:
            errors.append("[X] Numbered list with performance metrics not found")
        else:
            checks_passed.append("[C] Numbered list with performance metrics found")
    
        if not validation_paragraph:
            errors.append("[X] Validation paragraph about staging deployment not found")
        else:
            checks_passed.append("[C] Validation paragraph about staging deployment found")
    
        # ALL requirements met!
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: add-implementation-timeline-to-prd-v2
# Description: Add Implementation Timeline section to PRD
# =============================================================================
def _validate_agent_add_implementation_timeline_to_prd(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate Implementation Timeline with:
    - heading_2 '⏱️ Implementation Timeline' after Design Specs
    - Purple callout with 📅 icon about Q3 2024
    - heading_3 '🏃 Sprint Breakdown' with 4 numbered items
    - Divider
    - heading_3 '⚡ Critical Path Items' with 3 unchecked todos
    - Quote block with Peter Drucker quote
    
    Returns 1.0 only if ALL requirements are met, otherwise 0.0
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Find PRD page
    try:
        prd_pages = _get_pages_by_filter(backend, {"title": "Comprehensive Product Requirements Document"})
        if not prd_pages:
            prd_pages = _get_pages_by_filter(backend, {"title": "Product Requirements Document"})
        if not prd_pages:
            prd_pages = _get_pages_by_filter(backend, {"title": "PRD"})
        if not prd_pages:
            errors.append("[X] Product Requirements Document page not found")
        else:
            checks_passed.append("[C] Product Requirements Document page found")
        prd_page = prd_pages[0]
    
        prd_id = prd_page.get("_id")
    
        # 2. Get blocks for page
        page_blocks = _get_blocks_by_filter(backend, {"pageId": prd_id})
    
        if len(page_blocks) < 10:
            errors.append(f"[X] PRD page needs sufficient blocks, found {len(page_blocks)}")
        else:
            checks_passed.append(f"[C] PRD page needs sufficient blocks, found {len(page_blocks)}")
    
        # 3. Find required elements
        h2_timeline = False
        purple_callout = False
        h3_sprint_breakdown = False
        sprint_numbered_items = 0
        divider_found = False
        h3_critical_path = False
        critical_todos = 0
        quote_drucker = False
    
        for block in page_blocks:
            block_type = block.get("type", "")
            block_content = block.get("content", "")
            block_properties = block.get("properties", {})
            content_lower = block_content.lower()
        
            # heading_2 Implementation Timeline
            if block_type == "heading2" and "⏱️" in block_content and "implementation timeline" in content_lower:
                h2_timeline = True
        
            # Purple callout about Q3 2024
            if block_type == "callout":
                bg_color = block_properties.get("backgroundColor", "") if isinstance(block_properties, dict) else ""
                icon = block_properties.get("icon", "") if isinstance(block_properties, dict) else ""
            
                if "purple" in bg_color.lower() and "📅" in str(icon):
                    if "q3 2024" in content_lower and "sprints" in content_lower:
                        purple_callout = True
        
            # heading_3 Sprint Breakdown
            if block_type == "heading3" and "🏃" in block_content and "sprint breakdown" in content_lower:
                h3_sprint_breakdown = True
        
            # Numbered list with sprints
            if block_type == "numberedList" and "sprint" in content_lower:
                sprint_numbered_items += 1
        
            # Divider
            if block_type == "divider":
                divider_found = True
        
            # heading_3 Critical Path Items
            if block_type == "heading3" and "⚡" in block_content and "critical path" in content_lower:
                h3_critical_path = True
        
            # Critical path todos
            if block_type == "todo":
                checked = block_properties.get("checked", False) if isinstance(block_properties, dict) else False
                if not checked:
                    if "🔴" in block_content and "database schema" in content_lower:
                        critical_todos += 1
                    elif "🟡" in block_content and "api architecture" in content_lower:
                        critical_todos += 1
                    elif "🟢" in block_content and "ui component" in content_lower:
                        critical_todos += 1
        
            # Quote with Drucker
            if block_type == "quote" and "peter drucker" in content_lower and "time" in content_lower:
                quote_drucker = True
    
        # Validate all elements
        if not h2_timeline:
            errors.append("[X] heading_2 '⏱️ Implementation Timeline' not found")
        else:
            checks_passed.append("[C] heading_2 '⏱️ Implementation Timeline' found")
    
        if not purple_callout:
            errors.append("[X] Purple callout with 📅 icon about Q3 2024 not found")
        else:
            checks_passed.append("[C] Purple callout with 📅 icon about Q3 2024 found")
    
        if not h3_sprint_breakdown:
            errors.append("[X] heading_3 '🏃 Sprint Breakdown' not found")
        else:
            checks_passed.append("[C] heading_3 '🏃 Sprint Breakdown' found")
    
        if sprint_numbered_items < 1:
            errors.append("[X] Numbered list with sprint breakdown not found")
        else:
            checks_passed.append("[C] Numbered list with sprint breakdown found")
    
        if not divider_found:
            errors.append("[X] Divider not found")
        else:
            checks_passed.append("[C] Divider found")
    
        if not h3_critical_path:
            errors.append("[X] heading_3 '⚡ Critical Path Items' not found")
        else:
            checks_passed.append("[C] heading_3 '⚡ Critical Path Items' found")
    
        if critical_todos < 3:
            errors.append(f"[X] Expected 3 critical path todos with color emojis, found {critical_todos}")
        else:
            checks_passed.append(f"[C] Found 3 critical path todos with color emojis as expected")
    
        if not quote_drucker:
            errors.append("[X] Quote block with Peter Drucker quote not found")
        else:
            checks_passed.append("[C] Quote block with Peter Drucker quote found")
    
        # ALL requirements met!
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: reorganize-bug-tracker-by-status-v2
# Description: Reorganize Bug Tracker todos by status
# =============================================================================
def _validate_agent_reorganize_bug_tracker_by_status(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate Bug Tracker reorganization with:
    - heading_2 '🔥 Critical Issues' at top with red callout
    - Numbered list of all unchecked todos
    - heading_2 '✅ Resolved Issues' with green callout
    - Bulleted list of all checked todos
    - Divider
    - Resolution rate paragraph with percentage and today's date
    
    Returns 1.0 only if ALL requirements are met, otherwise 0.0
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Find Bug Tracker page
    try:
        bug_tracker_pages = _get_pages_by_filter(backend, {"title": "Bug Tracker"})
        if not bug_tracker_pages:
            errors.append("[X] Bug Tracker page not found")
        else:
            checks_passed.append("[C] Bug Tracker page found")
        bug_tracker = bug_tracker_pages[0]
    
        bug_tracker_id = bug_tracker.get("_id")
    
        # 2. Get blocks for page
        page_blocks = _get_blocks_by_filter(backend, {"pageId": bug_tracker_id})
    
        if len(page_blocks) < 6:
            errors.append(f"[X] Bug Tracker page needs sufficient blocks, found {len(page_blocks)}")
        else:
            checks_passed.append(f"[C] Bug Tracker page needs sufficient blocks, found {len(page_blocks)}")
    
        # 3. Find required elements and track positions
        h2_critical = False
        critical_idx = -1
        red_callout = False
        numbered_list_critical = False
    
        h2_resolved = False
        resolved_idx = -1
        green_callout = False
        bulleted_list_resolved = False
    
        divider_found = False
        resolution_paragraph = False
    
        for idx, block in enumerate(page_blocks):
            block_type = block.get("type", "")
            block_content = block.get("content", "")
            block_properties = block.get("properties", {})
            content_lower = block_content.lower()
        
            # heading_2 Critical Issues
            if block_type == "heading2" and "🔥" in block_content and "critical issues" in content_lower:
                h2_critical = True
                critical_idx = idx
        
            # Red callout
            if block_type == "callout":
                bg_color = block_properties.get("backgroundColor", "") if isinstance(block_properties, dict) else ""
                icon = block_properties.get("icon", "") if isinstance(block_properties, dict) else ""
            
                if "red" in bg_color.lower() and "⚠️" in str(icon):
                    if "urgent" in content_lower:
                        red_callout = True
            
                if "green" in bg_color.lower() and "🎉" in str(icon):
                    if "success" in content_lower or "fixed" in content_lower:
                        green_callout = True
        
            # heading_2 Resolved Issues
            if block_type == "heading2" and "✅" in block_content and "resolved issues" in content_lower:
                h2_resolved = True
                resolved_idx = idx
        
            # Numbered list for critical
            if block_type == "numberedList":
                numbered_list_critical = True
        
            # Bulleted list for resolved
            if block_type == "bulletedList":
                bulleted_list_resolved = True
        
            # Divider
            if block_type == "divider":
                divider_found = True
        
            # Resolution rate paragraph
            if block_type == "paragraph" and "resolution rate" in content_lower and "%" in block_content:
                resolution_paragraph = True
    
        # Validate Critical Issues section is at top
        if not h2_critical:
            errors.append("[X] heading_2 '🔥 Critical Issues' not found")
        else:
            checks_passed.append("[C] heading_2 '🔥 Critical Issues' found")
    
        if critical_idx > 2:
            errors.append("[X] Critical Issues section should be at the top of the page")
        else:
            checks_passed.append("[C] Critical Issues section should be at the top of the page")
    
        if not red_callout:
            errors.append("[X] Red callout with ⚠️ icon about urgent fixes not found")
        else:
            checks_passed.append("[C] Red callout with ⚠️ icon about urgent fixes found")
    
        if not numbered_list_critical:
            errors.append("[X] Numbered list for critical issues not found")
        else:
            checks_passed.append("[C] Numbered list for critical issues found")
    
        if not h2_resolved:
            errors.append("[X] heading_2 '✅ Resolved Issues' not found")
        else:
            checks_passed.append("[C] heading_2 '✅ Resolved Issues' found")
    
        if not green_callout:
            errors.append("[X] Green callout with 🎉 icon about successfully fixed not found")
        else:
            checks_passed.append("[C] Green callout with 🎉 icon about successfully fixed found")
    
        if not bulleted_list_resolved:
            errors.append("[X] Bulleted list for resolved issues not found")
        else:
            checks_passed.append("[C] Bulleted list for resolved issues found")
    
        if not divider_found:
            errors.append("[X] Divider not found")
        else:
            checks_passed.append("[C] Divider found")
    
        if not resolution_paragraph:
            errors.append("[X] Resolution rate paragraph with percentage not found")
        else:
            checks_passed.append("[C] Resolution rate paragraph with percentage found")
    
        # ALL requirements met!
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: create-task-analytics-dashboard-v2
# Description: Create a comprehensive Task Analytics Dashboard page analyzing ALL 
# pages with to-do blocks, showing statistics, top pages by task count, and 
# completion leaders
# =============================================================================
def _validate_agent_create_task_analytics_dashboard(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate Task Analytics Dashboard creation with:
    - Page created as child of 'Getting Started'
    - heading_1 '📊 Task Analytics Dashboard'
    - heading_2 '📈 Overall Statistics' with paragraph containing current date
    - Bulleted list with total pages, task counts, and percentages
    - heading_2 '📑 Pages with Most Tasks' with numbered list of top 5 pages
    - heading_3 '🎯 Completion Leaders' with bulleted list of 100% completion pages
    
    Returns 1.0 only if ALL requirements are met, otherwise 0.0
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Find the Task Analytics Dashboard page
    try:
        dashboard_pages = _get_pages_by_filter(backend, {"title": "Task Analytics Dashboard"})
        if not dashboard_pages:
            errors.append("[X] Task Analytics Dashboard page not found")
        else:
            checks_passed.append("[C] Task Analytics Dashboard page found")
        dashboard_page = dashboard_pages[0]
    
        dashboard_id = dashboard_page.get("_id")
    
        # 2. Verify it's a child of Getting Started
        getting_started_pages = _get_pages_by_filter(backend, {"title": "Getting Started"})
        if not getting_started_pages:
            errors.append("[X] Getting Started page not found")
        else:
            checks_passed.append("[C] Getting Started page found")
        getting_started = getting_started_pages[0]
    
        is_child = _check_page_is_child_of(getting_started, dashboard_page)
        if not is_child:
            errors.append("[X] Task Analytics Dashboard is not a child of Getting Started")
        else:
            checks_passed.append("[C] Task Analytics Dashboard is a child of Getting Started")
    
        # 3. Get blocks for the dashboard page
        page_blocks = _get_blocks_by_filter(backend, {"pageId": dashboard_id})
    
        if len(page_blocks) < 6:
            errors.append(f"[X] Dashboard needs sufficient blocks, found {len(page_blocks)}")
        else:
            checks_passed.append(f"[C] Dashboard needs sufficient blocks, found {len(page_blocks)}")
    
        # 4. Validate required elements
        h1_dashboard = False
        h2_statistics = False
        h2_most_tasks = False
        h3_completion_leaders = False
        has_date_paragraph = False
        has_bulleted_statistics = False
        has_numbered_top_pages = False
        has_bulleted_leaders = False
    
        for block in page_blocks:
            block_type = block.get("type", "")
            block_content = block.get("content", "")
            content_lower = block_content.lower()
        
            # heading_1 Task Analytics Dashboard
            if block_type == "heading1" and "📊" in block_content and "task analytics dashboard" in content_lower:
                h1_dashboard = True
        
            # heading_2 Overall Statistics
            if block_type == "heading2" and "📈" in block_content and "overall statistics" in content_lower:
                h2_statistics = True
        
            # heading_2 Pages with Most Tasks
            if block_type == "heading2" and "📑" in block_content and "pages with most tasks" in content_lower:
                h2_most_tasks = True
        
            # heading_3 Completion Leaders
            if block_type == "heading3" and "🎯" in block_content and "completion leaders" in content_lower:
                h3_completion_leaders = True
        
            # Paragraph with date
            if block_type == "paragraph" and "last updated" in content_lower:
                has_date_paragraph = True
        
            # Bulleted list with statistics
            if block_type == "bulletedList":
                if "total pages" in content_lower or "total task" in content_lower or "completed tasks" in content_lower:
                    has_bulleted_statistics = True
                elif h3_completion_leaders:
                    has_bulleted_leaders = True
        
            # Numbered list for top pages
            if block_type == "numberedList" and "tasks" in content_lower:
                has_numbered_top_pages = True
    
        if not h1_dashboard:
            errors.append("[X] heading_1 '📊 Task Analytics Dashboard' not found")
        else:
            checks_passed.append("[C] heading_1 '📊 Task Analytics Dashboard' found")
    
        if not h2_statistics:
            errors.append("[X] heading_2 '📈 Overall Statistics' not found")
        else:
            checks_passed.append("[C] heading_2 '📈 Overall Statistics' found")
    
        if not has_date_paragraph:
            errors.append("[X] Paragraph with 'Last updated:' and current date not found")
        else:
            checks_passed.append("[C] Paragraph with 'Last updated:' and current date found")
    
        if not has_bulleted_statistics:
            errors.append("[X] Bulleted list with task statistics not found")
        else:
            checks_passed.append("[C] Bulleted list with task statistics found")
    
        if not h2_most_tasks:
            errors.append("[X] heading_2 '📑 Pages with Most Tasks' not found")
        else:
            checks_passed.append("[C] heading_2 '📑 Pages with Most Tasks' found")
    
        if not has_numbered_top_pages:
            errors.append("[X] Numbered list of top pages by task count not found")
        else:
            checks_passed.append("[C] Numbered list of top pages by task count found")
    
        if not h3_completion_leaders:
            errors.append("[X] heading_3 '🎯 Completion Leaders' not found")
        else:
            checks_passed.append("[C] heading_3 '🎯 Completion Leaders' found")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: add-sprint-analysis-to-sprint-planning-v2
# Description: Add a comprehensive sprint analysis section to Sprint Planning - Jan 15
# with attendee count, goals count, and action items status breakdown
# =============================================================================
def _validate_agent_add_sprint_analysis_to_sprint_planning(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate Sprint Analysis addition with:
    - Divider added after existing content
    - heading_2 '📊 Sprint Analysis'
    - Blue callout with 👥 icon showing attendee count
    - Green callout with 🎯 icon showing goals count
    - heading_3 '✅ Action Items Status'
    - Bulleted list showing person, task, and status for each todo
    
    Returns 1.0 only if ALL requirements are met, otherwise 0.0
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Find Sprint Planning - Jan 15 page
    try:
        sprint_pages = _get_pages_by_filter(backend, {"title": "Sprint Planning - Jan 15"})
        if not sprint_pages:
            errors.append("[X] Sprint Planning - Jan 15 page not found")
        else:
            checks_passed.append("[C] Sprint Planning - Jan 15 page found")
        sprint_page = sprint_pages[0]
    
        sprint_id = sprint_page.get("_id")
        page_blocks = _get_blocks_by_filter(backend, {"pageId": sprint_id})
    
        if len(page_blocks) < 5:
            errors.append(f"[X] Page needs sufficient blocks, found {len(page_blocks)}")
        else:
            checks_passed.append(f"[C] Page needs sufficient blocks, found {len(page_blocks)}")
    
        # 2. Validate required elements
        divider_found = False
        h2_sprint_analysis = False
        blue_callout_attendees = False
        green_callout_goals = False
        h3_action_items_status = False
        bulleted_status_list = False
    
        for block in page_blocks:
            block_type = block.get("type", "")
            block_content = block.get("content", "")
            block_properties = block.get("properties", {})
            content_lower = block_content.lower()
        
            if block_type == "divider":
                divider_found = True
        
            if block_type == "heading2" and "📊" in block_content and "sprint analysis" in content_lower:
                h2_sprint_analysis = True
        
            if block_type == "callout":
                bg_color = block_properties.get("backgroundColor", "") if isinstance(block_properties, dict) else ""
                icon = block_properties.get("icon", "") if isinstance(block_properties, dict) else ""
            
                if "blue" in bg_color.lower() and "👥" in str(icon) and "attendee" in content_lower:
                    blue_callout_attendees = True
            
                if "green" in bg_color.lower() and "🎯" in str(icon) and "goal" in content_lower:
                    green_callout_goals = True
        
            if block_type == "heading3" and "✅" in block_content and "action items status" in content_lower:
                h3_action_items_status = True
        
            if block_type == "bulletedList" and ("completed" in content_lower or "pending" in content_lower):
                bulleted_status_list = True
    
        if not divider_found:
            errors.append("[X] Divider not found after existing content")
        else:
            checks_passed.append("[C] Divider found after existing content")
    
        if not h2_sprint_analysis:
            errors.append("[X] heading_2 '📊 Sprint Analysis' not found")
        else:
            checks_passed.append("[C] heading_2 '📊 Sprint Analysis' found")
    
        if not blue_callout_attendees:
            errors.append("[X] Blue callout with 👥 icon showing attendee count not found")
        else:
            checks_passed.append("[C] Blue callout with 👥 icon showing attendee count found")
    
        if not green_callout_goals:
            errors.append("[X] Green callout with 🎯 icon showing goals count not found")
        else:
            checks_passed.append("[C] Green callout with 🎯 icon showing goals count found")
    
        if not h3_action_items_status:
            errors.append("[X] heading_3 '✅ Action Items Status' not found")
        else:
            checks_passed.append("[C] heading_3 '✅ Action Items Status' found")
    
        if not bulleted_status_list:
            errors.append("[X] Bulleted list showing action items status not found")
        else:
            checks_passed.append("[C] Bulleted list showing action items status found")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: create-habit-tracker-weekly-planning-v2
# Description: Create Weekly Planning Dashboard with habit tracker as child of 
# Getting Started with specific structure and todo blocks
# =============================================================================
def _validate_agent_create_habit_tracker_weekly_planning(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate Weekly Planning Dashboard creation with:
    - Page created as child of Getting Started with 📅 icon
    - heading_1 '🎯 Weekly Planning Dashboard'
    - heading_2 '☑️ Habit Tracker'
    - Two date sections and 4 unchecked todos each (TODO: should check for bold date formatting in future)
    - Yellow callout with 💡 icon at the end
    
    Returns 1.0 only if ALL requirements are met, otherwise 0.0
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Find the Weekly Planning Dashboard page
    try:
        dashboard_pages = _get_pages_by_filter(backend, {"title": "Weekly Planning Dashboard"})
        if not dashboard_pages:
            errors.append("[X] Weekly Planning Dashboard page not found")
        else:
            checks_passed.append("[C] Weekly Planning Dashboard page found")
        dashboard_page = dashboard_pages[0]
    
        dashboard_id = dashboard_page.get("_id")
    
        # 2. Check for 📅 icon
        icon = dashboard_page.get("icon")
        if not icon:
            errors.append("[X] Weekly Planning Dashboard does not have an icon")
        else:
            checks_passed.append("[C] Weekly Planning Dashboard has an icon")
    
        icon_value = icon.get("value", "") if isinstance(icon, dict) else str(icon)
        if "📅" not in icon_value:
            errors.append(f"[X] Weekly Planning Dashboard should have 📅 icon (found: {icon_value})")
        else:
            checks_passed.append(f"[C] Weekly Planning Dashboard should have 📅 icon (found: {icon_value})")
    
        # 3. Verify it's a child of Getting Started
        getting_started_pages = _get_pages_by_filter(backend, {"title": "Getting Started"})
        if not getting_started_pages:
            errors.append("[X] Getting Started page not found")
        else:
            checks_passed.append("[C] Getting Started page found")
        getting_started = getting_started_pages[0]
    
        is_child = _check_page_is_child_of(getting_started, dashboard_page)
        if not is_child:
            errors.append("[X] Weekly Planning Dashboard is not a child of Getting Started")
        else:
            checks_passed.append("[C] Weekly Planning Dashboard is a child of Getting Started")
    
        # 4. Get blocks and validate structure
        page_blocks = _get_blocks_by_filter(backend, {"pageId": dashboard_id})
    
        h1_dashboard = False
        h2_habit_tracker = False
        has_date_jan_15 = False
        has_date_jan_16 = False
        divider_found = False
        yellow_callout = False
        todo_count = 0
    
        for block in page_blocks:
            block_type = block.get("type", "")
            block_content = block.get("content", "")
            block_properties = block.get("properties", {})
            content_lower = block_content.lower()
        
            if block_type == "heading1" and "🎯" in block_content and "weekly planning dashboard" in content_lower:
                h1_dashboard = True
        
            if block_type == "heading2" and "☑️" in block_content and "habit tracker" in content_lower:
                h2_habit_tracker = True
        
            if block_type == "paragraph" and "2024-01-15" in block_content:
                has_date_jan_15 = True
        
            if block_type == "paragraph" and "2024-01-16" in block_content:
                has_date_jan_16 = True
        
            if block_type == "divider":
                divider_found = True
        
            if block_type == "todo":
                todo_count += 1
        
            if block_type == "callout":
                bg_color = block_properties.get("backgroundColor", "") if isinstance(block_properties, dict) else ""
                icon_prop = block_properties.get("icon", "") if isinstance(block_properties, dict) else ""
            
                if "yellow" in bg_color.lower() and "💡" in str(icon_prop):
                    yellow_callout = True
    
        if not h1_dashboard:
            errors.append("[X] heading_1 '🎯 Weekly Planning Dashboard' not found")
        else:
            checks_passed.append("[C] heading_1 '🎯 Weekly Planning Dashboard' found")
    
        if not h2_habit_tracker:
            errors.append("[X] heading_2 '☑️ Habit Tracker' not found")
        else:
            checks_passed.append("[C] heading_2 '☑️ Habit Tracker' found")
    
        if not has_date_jan_15:
            errors.append("[X] Date section '2024-01-15' not found")
        else:
            checks_passed.append("[C] Date section '2024-01-15' found")
    
        if not has_date_jan_16:
            errors.append("[X] Date section '2024-01-16' not found")
        else:
            checks_passed.append("[C] Date section '2024-01-16' found")
    
        if not divider_found:
            errors.append("[X] Divider between date sections not found")
        else:
            checks_passed.append("[C] Divider between date sections found")
    
        if todo_count < 8:
            errors.append(f"[X] Expected at least 8 todo blocks (4 per date), found {todo_count}")
        else:
            checks_passed.append(f"[C] Found at least 8 todo blocks (4 per date) ({todo_count})")
    
        if not yellow_callout:
            errors.append("[X] Yellow callout with 💡 icon not found at the end")
        else:
            checks_passed.append("[C] Yellow callout with 💡 icon found at the end")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: reorganize-company-handbook-complex-v2
# Description: Perform complex reorganization on Company Handbook - swap Our Values 
# with Benefits, add Performance Standards section, and add callout to Time Off
# =============================================================================
def _validate_agent_reorganize_company_handbook_complex(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate complex Company Handbook reorganization with:
    - Our Values and Benefits sections swapped
    - New 'Performance Standards' section between Benefits and Work Policies
    - Performance Standards has heading_2, paragraph, and 3 numbered list items
    - Green callout added to Time Off subsection
    
    Returns 1.0 only if ALL requirements are met, otherwise 0.0
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Find Company Handbook page
    try:
        handbook_pages = _get_pages_by_filter(backend, {"title": "Company Handbook"})
        if not handbook_pages:
            errors.append("[X] Company Handbook page not found")
        else:
            checks_passed.append("[C] Company Handbook page found")
        handbook_page = handbook_pages[0]
    
        handbook_id = handbook_page.get("_id")
        page_blocks = _get_blocks_by_filter(backend, {"pageId": handbook_id})
    
        if len(page_blocks) < 10:
            errors.append(f"[X] Handbook needs sufficient blocks, found {len(page_blocks)}")
        else:
            checks_passed.append(f"[C] Handbook needs sufficient blocks, found {len(page_blocks)}")
    
        # 2. Track positions and find required elements
        our_values_idx = -1
        benefits_idx = -1
        performance_standards_idx = -1
        work_policies_idx = -1
        time_off_idx = -1
    
        h2_performance_standards = False
        performance_paragraph = False
        performance_numbered_items = 0
        green_callout_time_off = False
    
        for idx, block in enumerate(page_blocks):
            block_type = block.get("type", "")
            block_content = block.get("content", "")
            block_properties = block.get("properties", {})
            content_lower = block_content.lower()
        
            if block_type == "heading2":
                if "our values" in content_lower:
                    our_values_idx = idx
                elif "benefits" in content_lower and "performance" not in content_lower:
                    benefits_idx = idx
                elif "🎯" in block_content and "performance standards" in content_lower:
                    h2_performance_standards = True
                    performance_standards_idx = idx
                elif "work policies" in content_lower:
                    work_policies_idx = idx
        
            if block_type == "heading3" and "time off" in content_lower:
                time_off_idx = idx
        
            if block_type == "paragraph" and "excellence" in content_lower and "improvement" in content_lower:
                performance_paragraph = True
        
            if block_type == "numberedList":
                if "deadline" in content_lower or "coverage" in content_lower or "critical issues" in content_lower:
                    performance_numbered_items += 1
        
            if block_type == "callout":
                bg_color = block_properties.get("backgroundColor", "") if isinstance(block_properties, dict) else ""
                icon = block_properties.get("icon", "") if isinstance(block_properties, dict) else ""
            
                if "green" in bg_color.lower() and "🌴" in str(icon) and "work-life balance" in content_lower:
                    green_callout_time_off = True
    
        # Validate sections exist
        if our_values_idx == -1:
            errors.append("[X] 'Our Values' section not found")
        else:
            checks_passed.append("[C] 'Our Values' section found")
    
        if benefits_idx == -1:
            errors.append("[X] 'Benefits' section not found")
        else:
            checks_passed.append("[C] 'Benefits' section found")
    
        # For swap validation: Benefits should now appear before Our Values
        if benefits_idx > our_values_idx:
            errors.append("[X] 'Benefits' section should appear before 'Our Values' after swap")
        else:
            checks_passed.append("[C] 'Benefits' section should appear before 'Our Values' after swap")
    
        if not h2_performance_standards:
            errors.append("[X] heading_2 '🎯 Performance Standards' not found")
        else:
            checks_passed.append("[C] heading_2 '🎯 Performance Standards' found")
    
        if not performance_paragraph:
            errors.append("[X] Performance Standards paragraph about excellence not found")
        else:
            checks_passed.append("[C] Performance Standards paragraph about excellence found")
    
        if performance_numbered_items < 3:
            errors.append(f"[X] Expected 3 numbered list items under Performance Standards, found {performance_numbered_items}")
        else:
            checks_passed.append(f"[C] Found 3 numbered list items under Performance Standards as expected")
    
        # Validate Performance Standards is between Benefits and Work Policies
        if work_policies_idx != -1 and performance_standards_idx != -1:
            if not (benefits_idx < performance_standards_idx < work_policies_idx):
                errors.append("[X] Performance Standards should be between Benefits and Work Policies")
            else:
                checks_passed.append("[C] Performance Standards should be between Benefits and Work Policies")
    
        if not green_callout_time_off:
            errors.append("[X] Green callout with 🌴 icon about work-life balance not found in Time Off subsection")
        else:
            checks_passed.append("[C] Green callout with 🌴 icon about work-life balance found in Time Off subsection")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: add-task-distribution-to-sprint-planning-v2
# Description: Add task distribution analysis by assignee to Sprint Planning - Jan 15
# with percentage breakdown and team completion rate
# =============================================================================
def _validate_agent_add_task_distribution_to_sprint_planning(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate Task Distribution addition with:
    - heading_2 '👥 Task Distribution' after Action items section
    - Numbered list with assignee breakdown format '[Name]: [X] tasks ([Y]% of total)'
    - Divider followed by green callout with team completion rate
    - Bookmark block after wireframes todo with Figma URL
    
    Returns 1.0 only if ALL requirements are met, otherwise 0.0
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Find Sprint Planning - Jan 15 page
    try:
        sprint_pages = _get_pages_by_filter(backend, {"title": "Sprint Planning - Jan 15"})
        if not sprint_pages:
            errors.append("[X] Sprint Planning - Jan 15 page not found")
        else:
            checks_passed.append("[C] Sprint Planning - Jan 15 page found")
        sprint_page = sprint_pages[0]
    
        sprint_id = sprint_page.get("_id")
        page_blocks = _get_blocks_by_filter(backend, {"pageId": sprint_id})
    
        # 2. Track required elements
        h2_task_distribution = False
        h2_action_items_idx = -1
        task_distribution_idx = -1
        numbered_list_with_percentages = False
        divider_found = False
        green_callout_completion = False
        bookmark_figma = False
    
        for idx, block in enumerate(page_blocks):
            block_type = block.get("type", "")
            block_content = block.get("content", "")
            block_properties = block.get("properties", {})
            content_lower = block_content.lower()
        
            if block_type == "heading2" and "action items" in content_lower:
                h2_action_items_idx = idx
        
            if block_type == "heading2" and "👥" in block_content and "task distribution" in content_lower:
                h2_task_distribution = True
                task_distribution_idx = idx
        
            if block_type == "numberedList" and "%" in block_content and "tasks" in content_lower:
                numbered_list_with_percentages = True
        
            if block_type == "divider":
                divider_found = True
        
            if block_type == "callout":
                bg_color = block_properties.get("backgroundColor", "") if isinstance(block_properties, dict) else ""
                icon = block_properties.get("icon", "") if isinstance(block_properties, dict) else ""
            
                if "green" in bg_color.lower() and "✅" in str(icon) and "completion rate" in content_lower:
                    green_callout_completion = True
        
            if block_type == "bookmark":
                url = block_properties.get("url", "") if isinstance(block_properties, dict) else ""
                if "figma" in url.lower():
                    bookmark_figma = True
    
        if not h2_task_distribution:
            errors.append("[X] heading_2 '👥 Task Distribution' not found")
        else:
            checks_passed.append("[C] heading_2 '👥 Task Distribution' found")
    
        # Validate positioning (Task Distribution should be after Action items)
        if h2_action_items_idx != -1 and task_distribution_idx != -1:
            if task_distribution_idx <= h2_action_items_idx:
                errors.append("[X] Task Distribution should appear after Action items section")
            else:
                checks_passed.append("[C] Task Distribution should appear after Action items section")
    
        if not numbered_list_with_percentages:
            errors.append("[X] Numbered list with assignee breakdown and percentages not found")
        else:
            checks_passed.append("[C] Numbered list with assignee breakdown and percentages found")
    
        if not divider_found:
            errors.append("[X] Divider before completion rate callout not found")
        else:
            checks_passed.append("[C] Divider before completion rate callout found")
    
        if not green_callout_completion:
            errors.append("[X] Green callout with ✅ icon showing team completion rate not found")
        else:
            checks_passed.append("[C] Green callout with ✅ icon showing team completion rate found")
    
        if not bookmark_figma:
            errors.append("[X] Bookmark with Figma URL not found")
        else:
            checks_passed.append("[C] Bookmark with Figma URL found")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: create-documentation-analytics-dashboard-v2
# Description: Create Documentation Analytics Dashboard analyzing sub-pages recursively
# under Project Documentation with hierarchy overview and content statistics
# =============================================================================
def _validate_agent_create_documentation_analytics_dashboard(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate Documentation Analytics Dashboard creation with:
    - Page created as direct child of Project Documentation
    - heading_1 '📊 Documentation Analytics Dashboard'
    - heading_2 '📈 Page Hierarchy Overview' with bulleted list
    - heading_2 '📋 Content Statistics' with numbered list
    - Yellow callout with ⚡ icon containing generation date
    
    Returns 1.0 only if ALL requirements are met, otherwise 0.0
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Find the Documentation Analytics Dashboard page
    try:
        dashboard_pages = _get_pages_by_filter(backend, {"title": "Documentation Analytics Dashboard"})
        if not dashboard_pages:
            # Also try with emoji
            dashboard_pages = _get_pages_by_filter(backend, {"title": "📊 Documentation Analytics Dashboard"})
        if not dashboard_pages:
            errors.append("[X] Documentation Analytics Dashboard page not found")
        else:
            checks_passed.append("[C] Documentation Analytics Dashboard page found")
        dashboard_page = dashboard_pages[0]
    
        dashboard_id = dashboard_page.get("_id")
    
        # 2. Verify it's a child of Project Documentation
        project_doc_pages = _get_pages_by_filter(backend, {"title": "Project Documentation"})
        if not project_doc_pages:
            errors.append("[X] Project Documentation page not found")
        else:
            checks_passed.append("[C] Project Documentation page found")
        project_doc = project_doc_pages[0]
    
        is_child = _check_page_is_child_of(project_doc, dashboard_page)
        if not is_child:
            errors.append("[X] Documentation Analytics Dashboard is not a child of Project Documentation")
        else:
            checks_passed.append("[C] Documentation Analytics Dashboard is a child of Project Documentation")
    
        # 3. Get blocks and validate structure
        page_blocks = _get_blocks_by_filter(backend, {"pageId": dashboard_id})
    
        h1_dashboard = False
        h2_hierarchy = False
        h2_statistics = False
        bulleted_hierarchy = False
        numbered_statistics = False
        yellow_callout = False
    
        for block in page_blocks:
            block_type = block.get("type", "")
            block_content = block.get("content", "")
            block_properties = block.get("properties", {})
            content_lower = block_content.lower()
        
            if block_type == "heading1" and "📊" in block_content and "documentation analytics dashboard" in content_lower:
                h1_dashboard = True
        
            if block_type == "heading2" and "📈" in block_content and "page hierarchy overview" in content_lower:
                h2_hierarchy = True
        
            if block_type == "heading2" and "📋" in block_content and "content statistics" in content_lower:
                h2_statistics = True
        
            if block_type == "bulletedList" and ("sub-pages" in content_lower or "→" in block_content):
                bulleted_hierarchy = True
        
            if block_type == "numberedList" and ("total pages" in content_lower or "hierarchy" in content_lower):
                numbered_statistics = True
        
            if block_type == "callout":
                bg_color = block_properties.get("backgroundColor", "") if isinstance(block_properties, dict) else ""
                icon = block_properties.get("icon", "") if isinstance(block_properties, dict) else ""
            
                if "yellow" in bg_color.lower() and "⚡" in str(icon) and "generated" in content_lower:
                    yellow_callout = True
    
        if not h1_dashboard:
            errors.append("[X] heading_1 '📊 Documentation Analytics Dashboard' not found")
        else:
            checks_passed.append("[C] heading_1 '📊 Documentation Analytics Dashboard' found")
    
        if not h2_hierarchy:
            errors.append("[X] heading_2 '📈 Page Hierarchy Overview' not found")
        else:
            checks_passed.append("[C] heading_2 '📈 Page Hierarchy Overview' found")
    
        if not bulleted_hierarchy:
            errors.append("[X] Bulleted list showing page hierarchy not found")
        else:
            checks_passed.append("[C] Bulleted list showing page hierarchy found")
    
        if not h2_statistics:
            errors.append("[X] heading_2 '📋 Content Statistics' not found")
        else:
            checks_passed.append("[C] heading_2 '📋 Content Statistics' found")
    
        if not numbered_statistics:
            errors.append("[X] Numbered list with content statistics not found")
        else:
            checks_passed.append("[C] Numbered list with content statistics found")
    
        if not yellow_callout:
            errors.append("[X] Yellow callout with ⚡ icon and generation date not found")
        else:
            checks_passed.append("[C] Yellow callout with ⚡ icon and generation date found")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: create-consolidated-roadmap-v2
# Description: Consolidate Q1 and Q2 goals from Project Roadmap sub-pages into 
# a unified 2024 roadmap with analytics and next milestone
# =============================================================================
def _validate_agent_create_consolidated_roadmap(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate Consolidated Roadmap creation with:
    - heading_2 '🎯 Consolidated 2024 Roadmap' on Project Roadmap page
    - heading_3 '📅 Q1 Status' with todos from Q1 Goals
    - heading_3 '📅 Q2 Status' with todos from Q2 Goals
    - Divider followed by heading_3 '📊 Roadmap Analytics'
    - Analytics paragraph with overall and per-quarter percentages
    - Green callout with 🚀 icon showing next unchecked milestone
    
    Returns 1.0 only if ALL requirements are met, otherwise 0.0
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    # 1. Find Project Roadmap page
    try:
        roadmap_page = _find_page_by_title(final_state_backend, "Project Roadmap")
        if not roadmap_page:
            errors.append("[X] Project Roadmap page not found")
        else:
            checks_passed.append("[C] Project Roadmap page found")
    
        roadmap_id = roadmap_page.get("_id")
        page_blocks = _get_blocks_for_page(final_state_backend, roadmap_id)
    
        # 2. Track required elements
        h2_consolidated = False
        h3_q1_status = False
        h3_q2_status = False
        h3_analytics = False
        divider_found = False
        analytics_paragraph = False
        green_callout_milestone = False
        has_todos = False
    
        for block in page_blocks:
            block_type = block.get("type", "")
            block_content = block.get("content", "")
            block_properties = block.get("properties", {})
            content_lower = block_content.lower()
        
            if block_type == "heading2" and "🎯" in block_content and "consolidated 2024 roadmap" in content_lower:
                h2_consolidated = True
        
            if block_type == "heading3" and "📅" in block_content and "q1 status" in content_lower:
                h3_q1_status = True
        
            if block_type == "heading3" and "📅" in block_content and "q2 status" in content_lower:
                h3_q2_status = True
        
            if block_type == "heading3" and "📊" in block_content and "roadmap analytics" in content_lower:
                h3_analytics = True
        
            if block_type == "divider":
                divider_found = True
        
            if block_type == "paragraph" and "overall completion" in content_lower and "%" in block_content:
                if "q1" in content_lower and "q2" in content_lower:
                    analytics_paragraph = True
        
            if block_type == "callout":
                bg_color = block_properties.get("backgroundColor", "") if isinstance(block_properties, dict) else ""
                icon = block_properties.get("icon", "") if isinstance(block_properties, dict) else ""
            
                if "green" in bg_color.lower() and "🚀" in str(icon) and "next milestone" in content_lower:
                    green_callout_milestone = True
        
            if block_type == "todo":
                has_todos = True
    
        if not h2_consolidated:
            errors.append("[X] heading_2 '🎯 Consolidated 2024 Roadmap' not found")
        else:
            checks_passed.append("[C] heading_2 '🎯 Consolidated 2024 Roadmap' found")
    
        if not h3_q1_status:
            errors.append("[X] heading_3 '📅 Q1 Status' not found")
        else:
            checks_passed.append("[C] heading_3 '📅 Q1 Status' found")
    
        if not h3_q2_status:
            errors.append("[X] heading_3 '📅 Q2 Status' not found")
        else:
            checks_passed.append("[C] heading_3 '📅 Q2 Status' found")
    
        if not has_todos:
            errors.append("[X] Todo items from Q1 and Q2 goals not found")
        else:
            checks_passed.append("[C] Todo items from Q1 and Q2 goals found")
    
        if not divider_found:
            errors.append("[X] Divider before Roadmap Analytics not found")
        else:
            checks_passed.append("[C] Divider before Roadmap Analytics found")
    
        if not h3_analytics:
            errors.append("[X] heading_3 '📊 Roadmap Analytics' not found")
        else:
            checks_passed.append("[C] heading_3 '📊 Roadmap Analytics' found")
    
        if not analytics_paragraph:
            errors.append("[X] Analytics paragraph with overall and per-quarter percentages not found")
        else:
            checks_passed.append("[C] Analytics paragraph with overall and per-quarter percentages found")
    
        if not green_callout_milestone:
            errors.append("[X] Green callout with 🚀 icon showing next milestone not found")
        else:
            checks_passed.append("[C] Green callout with 🚀 icon showing next milestone found")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: create-feature-request-dashboard-v2
# Description: Create Feature Request Dashboard with comparison to Bug Tracker,
# priority matrix, and next steps
# =============================================================================
def _validate_agent_create_feature_request_dashboard(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate Feature Request Dashboard creation with:
    - Page created as child of Feature Requests
    - heading_1 '✨ Feature Request Dashboard' with timestamp
    - heading_2 '📈 Comparative Analysis' with yellow and red callouts
    - heading_2 '🎯 Priority Matrix' with four heading_3 quadrants
    - Numbered list under green quadrant
    - heading_2 '🚀 Next Steps' with 3 unchecked todos
    
    Returns 1.0 only if ALL requirements are met, otherwise 0.0
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Find the Feature Request Dashboard page
    try:
        dashboard_pages = _get_pages_by_filter(backend, {"title": "Feature Request Dashboard"})
        if not dashboard_pages:
            errors.append("[X] Feature Request Dashboard page not found")
        else:
            checks_passed.append("[C] Feature Request Dashboard page found")
        dashboard_page = dashboard_pages[0]
    
        dashboard_id = dashboard_page.get("_id")
    
        # 2. Verify it's a child of Feature Requests
        feature_requests_pages = _get_pages_by_filter(backend, {"title": "Feature Requests"})
        if not feature_requests_pages:
            errors.append("[X] Feature Requests page not found")
        else:
            checks_passed.append("[C] Feature Requests page found")
        feature_requests = feature_requests_pages[0]
    
        is_child = _check_page_is_child_of(feature_requests, dashboard_page)
        if not is_child:
            errors.append("[X] Feature Request Dashboard is not a child of Feature Requests")
        else:
            checks_passed.append("[C] Feature Request Dashboard is a child of Feature Requests")
    
        # 3. Get blocks and validate structure
        page_blocks = _get_blocks_by_filter(backend, {"pageId": dashboard_id})
    
        h1_dashboard = False
        h2_comparative = False
        h2_priority_matrix = False
        h2_next_steps = False
        yellow_callout_features = False
        red_callout_bugs = False
        h3_high_impact_high_effort = False
        h3_high_impact_low_effort = False
        h3_low_impact_high_effort = False
        h3_low_impact_low_effort = False
        numbered_quick_wins = False
        todo_count = 0
    
        for block in page_blocks:
            block_type = block.get("type", "")
            block_content = block.get("content", "")
            block_properties = block.get("properties", {})
            content_lower = block_content.lower()
        
            if block_type == "heading1" and "✨" in block_content and "feature request dashboard" in content_lower:
                h1_dashboard = True
        
            if block_type == "heading2" and "📈" in block_content and "comparative analysis" in content_lower:
                h2_comparative = True
        
            if block_type == "heading2" and "🎯" in block_content and "priority matrix" in content_lower:
                h2_priority_matrix = True
        
            if block_type == "heading2" and "🚀" in block_content and "next steps" in content_lower:
                h2_next_steps = True
        
            if block_type == "callout":
                bg_color = block_properties.get("backgroundColor", "") if isinstance(block_properties, dict) else ""
            
                if "yellow" in bg_color.lower() and "feature" in content_lower:
                    yellow_callout_features = True
                if "red" in bg_color.lower() and "bug" in content_lower:
                    red_callout_bugs = True
        
            if block_type == "heading3":
                if "🔴" in block_content and "high impact" in content_lower and "high effort" in content_lower:
                    h3_high_impact_high_effort = True
                if "🟢" in block_content and "high impact" in content_lower and "low effort" in content_lower:
                    h3_high_impact_low_effort = True
                if "🟡" in block_content and "low impact" in content_lower and "high effort" in content_lower:
                    h3_low_impact_high_effort = True
                if "🔵" in block_content and "low impact" in content_lower and "low effort" in content_lower:
                    h3_low_impact_low_effort = True
        
            if block_type == "numberedList" and ("quick wins" in content_lower or "sprint" in content_lower):
                numbered_quick_wins = True
        
            if block_type == "todo":
                todo_count += 1
    
        if not h1_dashboard:
            errors.append("[X] heading_1 '✨ Feature Request Dashboard' not found")
        else:
            checks_passed.append("[C] heading_1 '✨ Feature Request Dashboard' found")
    
        if not h2_comparative:
            errors.append("[X] heading_2 '📈 Comparative Analysis' not found")
        else:
            checks_passed.append("[C] heading_2 '📈 Comparative Analysis' found")
    
        if not yellow_callout_features:
            errors.append("[X] Yellow callout with feature request counts not found")
        else:
            checks_passed.append("[C] Yellow callout with feature request counts found")
    
        if not red_callout_bugs:
            errors.append("[X] Red callout with bug tracker counts not found")
        else:
            checks_passed.append("[C] Red callout with bug tracker counts found")
    
        if not h2_priority_matrix:
            errors.append("[X] heading_2 '🎯 Priority Matrix' not found")
        else:
            checks_passed.append("[C] heading_2 '🎯 Priority Matrix' found")
    
        if not (h3_high_impact_high_effort and h3_high_impact_low_effort and h3_low_impact_high_effort and h3_low_impact_low_effort):
            errors.append("[X] Not all four priority matrix quadrants found")
        else:
            checks_passed.append("[C] all four priority matrix quadrants found")
    
        if not numbered_quick_wins:
            errors.append("[X] Numbered list under green quadrant not found")
        else:
            checks_passed.append("[C] Numbered list under green quadrant found")
    
        if not h2_next_steps:
            errors.append("[X] heading_2 '🚀 Next Steps' not found")
        else:
            checks_passed.append("[C] heading_2 '🚀 Next Steps' found")
    
        if todo_count < 3:
            errors.append(f"[X] Expected at least 3 todo items under Next Steps, found {todo_count}")
        else:
            checks_passed.append(f"[C] Found at least 3 todo items under Next Steps ({todo_count})")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: reorganize-design-system-v2
# Description: Reorganize Design System page with new Design System 2.0 section,
# moving legacy content and adding resources
# =============================================================================
def _validate_agent_reorganize_design_system(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate Design System reorganization with:
    - heading_2 '🚀 Design System 2.0' with green callout
    - heading_3 '🎯 Core Principles' with numbered list
    - heading_3 '🔗 Resources' with bookmarks (Figma and Storybook)
    - Divider followed by quote block
    - heading_2 '🎨 Legacy Design Guidelines' with all original content
    
    Returns 1.0 only if ALL requirements are met, otherwise 0.0
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Find Design System page
    try:
        design_pages = _get_pages_by_filter(backend, {"title": "Design System"})
        if not design_pages:
            errors.append("[X] Design System page not found")
        else:
            checks_passed.append("[C] Design System page found")
        design_page = design_pages[0]
    
        design_id = design_page.get("_id")
        page_blocks = _get_blocks_by_filter(backend, {"pageId": design_id})
    
        # 2. Track required elements and positions
        h2_design_system_2 = False
        h2_design_system_2_idx = -1
        h2_legacy_idx = -1
        h3_core_principles = False
        h3_resources = False
        green_callout_launch = False
        numbered_principles = False
        bookmark_figma = False
        bookmark_storybook = False
        divider_found = False
        quote_block = False
        h2_legacy = False
    
        for idx, block in enumerate(page_blocks):
            block_type = block.get("type", "")
            block_content = block.get("content", "")
            block_properties = block.get("properties", {})
            content_lower = block_content.lower()
        
            if block_type == "heading2" and "🚀" in block_content and "design system 2.0" in content_lower:
                h2_design_system_2 = True
                h2_design_system_2_idx = idx
        
            if block_type == "heading2" and "🎨" in block_content and "legacy design guidelines" in content_lower:
                h2_legacy = True
                h2_legacy_idx = idx
        
            if block_type == "heading3" and "🎯" in block_content and "core principles" in content_lower:
                h3_core_principles = True
        
            if block_type == "heading3" and "🔗" in block_content and "resources" in content_lower:
                h3_resources = True
        
            if block_type == "callout":
                bg_color = block_properties.get("backgroundColor", "") if isinstance(block_properties, dict) else ""
                icon = block_properties.get("icon", "") if isinstance(block_properties, dict) else ""
            
                if "green" in bg_color.lower() and "✨" in str(icon) and "january 2024" in content_lower:
                    green_callout_launch = True
        
            if block_type == "numberedList" and ("consistency" in content_lower or "accessibility" in content_lower):
                numbered_principles = True
        
            if block_type == "bookmark":
                url = block_properties.get("url", "") if isinstance(block_properties, dict) else ""
                if "figma" in url.lower():
                    bookmark_figma = True
                if "storybook" in url.lower():
                    bookmark_storybook = True
        
            if block_type == "divider":
                divider_found = True
        
            if block_type == "quote" and "good design" in content_lower:
                quote_block = True
    
        # Validate new Design System 2.0 appears before Legacy
        if h2_design_system_2_idx != -1 and h2_legacy_idx != -1:
            if h2_design_system_2_idx > h2_legacy_idx:
                errors.append("[X] Design System 2.0 section should appear before Legacy Design Guidelines")
            else:
                checks_passed.append("[C] Design System 2.0 section should appear before Legacy Design Guidelines")
    
        if not h2_design_system_2:
            errors.append("[X] heading_2 '🚀 Design System 2.0' not found")
        else:
            checks_passed.append("[C] heading_2 '🚀 Design System 2.0' found")
    
        if not green_callout_launch:
            errors.append("[X] Green callout with ✨ icon about January 2024 launch not found")
        else:
            checks_passed.append("[C] Green callout with ✨ icon about January 2024 launch found")
    
        if not h3_core_principles:
            errors.append("[X] heading_3 '🎯 Core Principles' not found")
        else:
            checks_passed.append("[C] heading_3 '🎯 Core Principles' found")
    
        if not numbered_principles:
            errors.append("[X] Numbered list with core principles not found")
        else:
            checks_passed.append("[C] Numbered list with core principles found")
    
        if not h3_resources:
            errors.append("[X] heading_3 '🔗 Resources' not found")
        else:
            checks_passed.append("[C] heading_3 '🔗 Resources' found")
    
        if not bookmark_figma:
            errors.append("[X] Bookmark with Figma Design Library URL not found")
        else:
            checks_passed.append("[C] Bookmark with Figma Design Library URL found")
    
        if not bookmark_storybook:
            errors.append("[X] Bookmark with Storybook URL not found")
        else:
            checks_passed.append("[C] Bookmark with Storybook URL found")
    
        if not divider_found:
            errors.append("[X] Divider between new section and legacy not found")
        else:
            checks_passed.append("[C] Divider between new section and legacy found")
    
        if not quote_block:
            errors.append("[X] Quote block about 'Good design is obvious. Great design is transparent.' not found")
        else:
            checks_passed.append("[C] Quote block about 'Good design is obvious. Great design is transparent.' found")
    
        if not h2_legacy:
            errors.append("[X] heading_2 '🎨 Legacy Design Guidelines' not found")
        else:
            checks_passed.append("[C] heading_2 '🎨 Legacy Design Guidelines' found")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: add-day-2-3-objectives-to-onboarding-v2
# Description: Add Day 2-3 Objectives section to Onboarding Guide after First Day Tasks
# but before First Week Goals, with todos and callout
# =============================================================================
def _validate_agent_add_day_2_3_objectives_to_onboarding(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate Day 2-3 Objectives addition with:
    - heading_2 '🗓️ Day 2-3 Objectives' positioned correctly
    - Paragraph 'Complete these tasks by end of Day 3:'
    - 3 unchecked todos with specific text and emojis
    - Blue callout with 💡 icon about IT helpdesk
    - First Day Tasks numbered items have emoji prefixes
    
    Returns 1.0 only if ALL requirements are met, otherwise 0.0
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Find Onboarding Guide page
    try:
        onboarding_pages = _get_pages_by_filter(backend, {"title": "Onboarding Guide"})
        if not onboarding_pages:
            errors.append("[X] Onboarding Guide page not found")
        else:
            checks_passed.append("[C] Onboarding Guide page found")
        onboarding_page = onboarding_pages[0]
    
        onboarding_id = onboarding_page.get("_id")
        page_blocks = _get_blocks_by_filter(backend, {"pageId": onboarding_id})
    
        # 2. Track positions and required elements
        first_day_tasks_idx = -1
        day_2_3_idx = -1
        first_week_goals_idx = -1
    
        h2_day_2_3 = False
        paragraph_complete_tasks = False
        todo_email = False
        todo_security = False
        todo_slack = False
        blue_callout_helpdesk = False
        emoji_numbered_items = 0
    
        for idx, block in enumerate(page_blocks):
            block_type = block.get("type", "")
            block_content = block.get("content", "")
            block_properties = block.get("properties", {})
            content_lower = block_content.lower()
        
            if block_type == "heading2" and "first day tasks" in content_lower:
                first_day_tasks_idx = idx
        
            if block_type == "heading2" and "🗓️" in block_content and "day 2-3 objectives" in content_lower:
                h2_day_2_3 = True
                day_2_3_idx = idx
        
            if block_type == "heading2" and "first week goals" in content_lower:
                first_week_goals_idx = idx
        
            if block_type == "paragraph" and "complete these tasks by end of day 3" in content_lower:
                paragraph_complete_tasks = True
        
            if block_type == "todo":
                if "📧" in block_content and "email" in content_lower:
                    todo_email = True
                if "🔐" in block_content and "security" in content_lower:
                    todo_security = True
                if "💬" in block_content and "slack" in content_lower:
                    todo_slack = True
        
            if block_type == "callout":
                bg_color = block_properties.get("backgroundColor", "") if isinstance(block_properties, dict) else ""
                icon = block_properties.get("icon", "") if isinstance(block_properties, dict) else ""
            
                if "blue" in bg_color.lower() and "💡" in str(icon) and "helpdesk" in content_lower:
                    blue_callout_helpdesk = True
        
            if block_type == "numberedList":
                if "1️⃣" in block_content or "2️⃣" in block_content or "3️⃣" in block_content:
                    emoji_numbered_items += 1
    
        if not h2_day_2_3:
            errors.append("[X] heading_2 '🗓️ Day 2-3 Objectives' not found")
        else:
            checks_passed.append("[C] heading_2 '🗓️ Day 2-3 Objectives' found")
    
        # Validate position: after First Day Tasks, before First Week Goals
        if first_day_tasks_idx != -1 and day_2_3_idx != -1 and first_week_goals_idx != -1:
            if not (first_day_tasks_idx < day_2_3_idx < first_week_goals_idx):
                errors.append("[X] Day 2-3 Objectives should be between First Day Tasks and First Week Goals")
            else:
                checks_passed.append("[C] Day 2-3 Objectives should be between First Day Tasks and First Week Goals")
    
        if not paragraph_complete_tasks:
            errors.append("[X] Paragraph 'Complete these tasks by end of Day 3:' not found")
        else:
            checks_passed.append("[C] Paragraph 'Complete these tasks by end of Day 3:' found")
    
        if not todo_email:
            errors.append("[X] Todo '📧 Set up email filters and calendar' not found")
        else:
            checks_passed.append("[C] Todo '📧 Set up email filters and calendar' found")
    
        if not todo_security:
            errors.append("[X] Todo '🔐 Complete security training module' not found")
        else:
            checks_passed.append("[C] Todo '🔐 Complete security training module' found")
    
        if not todo_slack:
            errors.append("[X] Todo '💬 Join all relevant Slack channels' not found")
        else:
            checks_passed.append("[C] Todo '💬 Join all relevant Slack channels' found")
    
        if not blue_callout_helpdesk:
            errors.append("[X] Blue callout with 💡 icon about IT helpdesk not found")
        else:
            checks_passed.append("[C] Blue callout with 💡 icon about IT helpdesk found")
    
        if emoji_numbered_items < 1:
            errors.append("[X] First Day Tasks numbered items should have emoji prefixes (1️⃣, 2️⃣, 3️⃣)")
        else:
            checks_passed.append("[C] First Day Tasks numbered items should have emoji prefixes (1️⃣, 2️⃣, 3️⃣)")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: reorganize-external-resources-swap-v2
# Description: Reorganize External Resources page by swapping Documentation and 
# Learning sections, deduplicating bookmarks, and moving Tools section
# =============================================================================
def _validate_agent_reorganize_external_resources_swap(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate External Resources reorganization with:
    - Learning section now appears where Documentation was (and vice versa)
    - Duplicate bookmarks removed from Learning section
    - Paragraph with today's date at start of Learning section (TODO: should check for italic formatting in future)
    - Tools section moved to first position after main heading
    
    Returns 1.0 only if ALL requirements are met, otherwise 0.0
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Find External Resources page
    try:
        resources_pages = _get_pages_by_filter(backend, {"title": "External Resources & Links"})
        if not resources_pages:
            resources_pages = _get_pages_by_filter(backend, {"title": "External Resources"})
        if not resources_pages:
            errors.append("[X] External Resources page not found")
        else:
            checks_passed.append("[C] External Resources page found")
        resources_page = resources_pages[0]
    
        resources_id = resources_page.get("_id")
        page_blocks = _get_blocks_by_filter(backend, {"pageId": resources_id})
    
        # 2. Track section positions
        main_heading_idx = -1
        tools_idx = -1
        learning_idx = -1
        documentation_idx = -1
    
        # TODO: Re-enable italic formatting check when ready - should verify italic formatting
        learning_intro_paragraph_found = False
    
        for idx, block in enumerate(page_blocks):
            block_type = block.get("type", "")
            block_content = block.get("content", "")
            content_lower = block_content.lower()
        
            if block_type == "heading1" and "external resources" in content_lower:
                main_heading_idx = idx
        
            if block_type == "heading2":
                if "tools" in content_lower:
                    tools_idx = idx
                elif "learning" in content_lower:
                    learning_idx = idx
                elif "documentation" in content_lower:
                    documentation_idx = idx
        
            if block_type == "paragraph" and "essential learning resources" in content_lower:
                learning_intro_paragraph_found = True
    
        # Validate Tools is first section after main heading
        if main_heading_idx != -1 and tools_idx != -1:
            # Tools should be the first heading_2 after main heading
            first_h2_after_main = -1
            for idx, block in enumerate(page_blocks):
                if idx > main_heading_idx and block.get("type") == "heading2":
                    first_h2_after_main = idx
                    break
        
            if tools_idx != first_h2_after_main:
                errors.append("[X] Tools section should be the first section after the main heading")
            else:
                checks_passed.append("[C] Tools section should be the first section after the main heading")
    
        # Validate Learning and Documentation were swapped
        # After swap, Learning should appear where Documentation was originally
        if learning_idx == -1:
            errors.append("[X] Learning section not found")
        else:
            checks_passed.append("[C] Learning section found")
    
        if documentation_idx == -1:
            errors.append("[X] Documentation section not found")
        else:
            checks_passed.append("[C] Documentation section found")
    
        # The swap means Learning now comes before Documentation (if original order was Doc before Learning)
        # We just check that the structure exists and intro paragraph is present
        # TODO: Re-enable italic formatting check when ready - should verify italic formatting
    
        if not learning_intro_paragraph_found:
            errors.append("[X] Paragraph with today's date at start of Learning section not found")
        else:
            checks_passed.append("[C] Paragraph with today's date at start of Learning section found")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: add-design-ux-updates-to-standup-v2
# Description: Add Design & UX Updates section to Weekly Standup Template after
# 'What I plan to do next week' but before 'Blockers'
# =============================================================================
def _validate_agent_add_design_ux_updates_to_standup(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate Design & UX Updates addition with:
    - heading_2 '🎨 Design & UX Updates' positioned correctly
    - 3 unchecked todos with specific text
    - Gray callout with 💡 icon containing pro tip
    
    Returns 1.0 only if ALL requirements are met, otherwise 0.0
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Find Weekly Standup Template page
    try:
        standup_pages = _get_pages_by_filter(backend, {"title": "Weekly Standup Template"})
        if not standup_pages:
            errors.append("[X] Weekly Standup Template page not found")
        else:
            checks_passed.append("[C] Weekly Standup Template page found")
        standup_page = standup_pages[0]
    
        standup_id = standup_page.get("_id")
        page_blocks = _get_blocks_by_filter(backend, {"pageId": standup_id})
    
        # 2. Track positions and elements
        next_week_idx = -1
        design_ux_idx = -1
        blockers_idx = -1
    
        h2_design_ux = False
        todo_mockups = False
        todo_color_palette = False
        todo_accessibility = False
        gray_callout_protip = False
    
        for idx, block in enumerate(page_blocks):
            block_type = block.get("type", "")
            block_content = block.get("content", "")
            block_properties = block.get("properties", {})
            content_lower = block_content.lower()
        
            if block_type == "heading2" and "what i plan to do next week" in content_lower:
                next_week_idx = idx
        
            if block_type == "heading2" and "🎨" in block_content and "design" in content_lower and "ux updates" in content_lower:
                h2_design_ux = True
                design_ux_idx = idx
        
            if block_type == "heading2" and "blockers" in content_lower:
                blockers_idx = idx
        
            if block_type == "todo":
                if "mockups" in content_lower and "dashboard" in content_lower:
                    todo_mockups = True
                if "color palette" in content_lower or "colour palette" in content_lower:
                    todo_color_palette = True
                if "accessibility" in content_lower:
                    todo_accessibility = True
        
            if block_type == "callout":
                bg_color = block_properties.get("backgroundColor", "") if isinstance(block_properties, dict) else ""
                icon = block_properties.get("icon", "") if isinstance(block_properties, dict) else ""
            
                if "gray" in bg_color.lower() and "💡" in str(icon) and "pro tip" in content_lower:
                    gray_callout_protip = True
    
        if not h2_design_ux:
            errors.append("[X] heading_2 '🎨 Design & UX Updates' not found")
        else:
            checks_passed.append("[C] heading_2 '🎨 Design & UX Updates' found")
    
        # Validate position
        if next_week_idx != -1 and design_ux_idx != -1 and blockers_idx != -1:
            if not (next_week_idx < design_ux_idx < blockers_idx):
                errors.append("[X] Design & UX Updates should be between 'What I plan to do next week' and 'Blockers'")
            else:
                checks_passed.append("[C] Design & UX Updates should be between 'What I plan to do next week' and 'Blockers'")
    
        if not todo_mockups:
            errors.append("[X] Todo about reviewing dashboard mockups not found")
        else:
            checks_passed.append("[C] Todo about reviewing dashboard mockups found")
    
        if not todo_color_palette:
            errors.append("[X] Todo about color palette feedback not found")
        else:
            checks_passed.append("[C] Todo about color palette feedback found")
    
        if not todo_accessibility:
            errors.append("[X] Todo about accessibility tools not found")
        else:
            checks_passed.append("[C] Todo about accessibility tools found")
    
        if not gray_callout_protip:
            errors.append("[X] Gray callout with 💡 icon containing pro tip not found")
        else:
            checks_passed.append("[C] Gray callout with 💡 icon containing pro tip found")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: add-performance-reviews-to-handbook-v2
# Description: Add Performance Reviews section to Company Handbook after Benefits
# section with heading, subheading, paragraph, numbered list, and callout
# =============================================================================
def _validate_agent_add_performance_reviews_to_handbook(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate Performance Reviews addition with:
    - heading_2 '⚡ Performance Reviews' positioned after Benefits
    - heading_3 'Quarterly Evaluation Process'
    - Paragraph about quarterly evaluations aligned with OKRs
    - 3 numbered list items with week timing
    - Blue callout with 📊 icon about compensation
    
    Returns 1.0 only if ALL requirements are met, otherwise 0.0
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Find Company Handbook page
    try:
        handbook_pages = _get_pages_by_filter(backend, {"title": "Company Handbook"})
        if not handbook_pages:
            errors.append("[X] Company Handbook page not found")
        else:
            checks_passed.append("[C] Company Handbook page found")
        handbook_page = handbook_pages[0]
    
        handbook_id = handbook_page.get("_id")
        page_blocks = _get_blocks_by_filter(backend, {"pageId": handbook_id})
    
        # 2. Track positions and elements
        benefits_idx = -1
        performance_reviews_idx = -1
    
        h2_performance_reviews = False
        h3_quarterly_process = False
        paragraph_okrs = False
        numbered_week_items = 0
        blue_callout_compensation = False
    
        for idx, block in enumerate(page_blocks):
            block_type = block.get("type", "")
            block_content = block.get("content", "")
            block_properties = block.get("properties", {})
            content_lower = block_content.lower()
        
            if block_type == "heading2" and "benefits" in content_lower and "performance" not in content_lower:
                benefits_idx = idx
        
            if block_type == "heading2" and "⚡" in block_content and "performance reviews" in content_lower:
                h2_performance_reviews = True
                performance_reviews_idx = idx
        
            if block_type == "heading3" and "quarterly evaluation process" in content_lower:
                h3_quarterly_process = True
        
            if block_type == "paragraph" and "quarterly" in content_lower and "okr" in content_lower:
                paragraph_okrs = True
        
            if block_type == "numberedList":
                if "first week" in content_lower or "second week" in content_lower or "third week" in content_lower:
                    numbered_week_items += 1
        
            if block_type == "callout":
                bg_color = block_properties.get("backgroundColor", "") if isinstance(block_properties, dict) else ""
                icon = block_properties.get("icon", "") if isinstance(block_properties, dict) else ""
            
                if "blue" in bg_color.lower() and "📊" in str(icon) and "compensation" in content_lower:
                    blue_callout_compensation = True
    
        if not h2_performance_reviews:
            errors.append("[X] heading_2 '⚡ Performance Reviews' not found")
        else:
            checks_passed.append("[C] heading_2 '⚡ Performance Reviews' found")
    
        # Validate position after Benefits
        if benefits_idx != -1 and performance_reviews_idx != -1:
            if performance_reviews_idx < benefits_idx:
                errors.append("[X] Performance Reviews should appear after Benefits section")
            else:
                checks_passed.append("[C] Performance Reviews should appear after Benefits section")
    
        if not h3_quarterly_process:
            errors.append("[X] heading_3 'Quarterly Evaluation Process' not found")
        else:
            checks_passed.append("[C] heading_3 'Quarterly Evaluation Process' found")
    
        if not paragraph_okrs:
            errors.append("[X] Paragraph about quarterly evaluations aligned with OKRs not found")
        else:
            checks_passed.append("[C] Paragraph about quarterly evaluations aligned with OKRs found")
    
        if numbered_week_items < 3:
            errors.append(f"[X] Expected 3 numbered list items with week timing, found {numbered_week_items}")
        else:
            checks_passed.append(f"[C] Found 3 numbered list items with week timing as expected")
    
        if not blue_callout_compensation:
            errors.append("[X] Blue callout with 📊 icon about compensation not found")
        else:
            checks_passed.append("[C] Blue callout with 📊 icon about compensation found")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: create-weekly-planning-dashboard-child-v2
# Description: Create Weekly Planning Dashboard as child of Weekly Standup Template
# analyzing todos and showing task breakdown
# =============================================================================
def _validate_agent_create_weekly_planning_dashboard_child(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate Weekly Planning Dashboard creation with:
    - Page created as child of Weekly Standup Template
    - heading_1 '📅 Weekly Planning Dashboard'
    - heading_2 '🎯 Week Overview' with orange callout showing completion rate
    - heading_2 '📊 Task Breakdown' with heading_3 subsections
    - heading_2 '💡 Planning Tips' with quote block
    
    Returns 1.0 only if ALL requirements are met, otherwise 0.0
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Find the Weekly Planning Dashboard page
    try:
        dashboard_pages = _get_pages_by_filter(backend, {"title": "Weekly Planning Dashboard"})
        if not dashboard_pages:
            errors.append("[X] Weekly Planning Dashboard page not found")
        else:
            checks_passed.append("[C] Weekly Planning Dashboard page found")
        dashboard_page = dashboard_pages[0]
    
        dashboard_id = dashboard_page.get("_id")
    
        # 2. Verify it's a child of Weekly Standup Template
        standup_template_pages = _get_pages_by_filter(backend, {"title": "Weekly Standup Template"})
        if not standup_template_pages:
            errors.append("[X] Weekly Standup Template page not found")
        else:
            checks_passed.append("[C] Weekly Standup Template page found")
        standup_template = standup_template_pages[0]
    
        is_child = _check_page_is_child_of(standup_template, dashboard_page)
        if not is_child:
            errors.append("[X] Weekly Planning Dashboard is not a child of Weekly Standup Template")
        else:
            checks_passed.append("[C] Weekly Planning Dashboard is a child of Weekly Standup Template")
    
        # 3. Get blocks and validate structure
        page_blocks = _get_blocks_by_filter(backend, {"pageId": dashboard_id})
    
        h1_dashboard = False
        h2_week_overview = False
        h2_task_breakdown = False
        h2_planning_tips = False
        h3_completed = False
        h3_in_progress = False
        h3_upcoming = False
        orange_callout_completion = False
        quote_tip = False
    
        for block in page_blocks:
            block_type = block.get("type", "")
            block_content = block.get("content", "")
            block_properties = block.get("properties", {})
            content_lower = block_content.lower()
        
            if block_type == "heading1" and "📅" in block_content and "weekly planning dashboard" in content_lower:
                h1_dashboard = True
        
            if block_type == "heading2" and "🎯" in block_content and "week overview" in content_lower:
                h2_week_overview = True
        
            if block_type == "heading2" and "📊" in block_content and "task breakdown" in content_lower:
                h2_task_breakdown = True
        
            if block_type == "heading2" and "💡" in block_content and "planning tips" in content_lower:
                h2_planning_tips = True
        
            if block_type == "heading3":
                if "✅" in block_content and "completed" in content_lower:
                    h3_completed = True
                if "🔄" in block_content and "in progress" in content_lower:
                    h3_in_progress = True
                if "📌" in block_content and "upcoming" in content_lower:
                    h3_upcoming = True
        
            if block_type == "callout":
                bg_color = block_properties.get("backgroundColor", "") if isinstance(block_properties, dict) else ""
            
                if "orange" in bg_color.lower() and "completion" in content_lower and "%" in block_content:
                    orange_callout_completion = True
        
            if block_type == "quote" and "completed tasks" in content_lower:
                quote_tip = True
    
        if not h1_dashboard:
            errors.append("[X] heading_1 '📅 Weekly Planning Dashboard' not found")
        else:
            checks_passed.append("[C] heading_1 '📅 Weekly Planning Dashboard' found")
    
        if not h2_week_overview:
            errors.append("[X] heading_2 '🎯 Week Overview' not found")
        else:
            checks_passed.append("[C] heading_2 '🎯 Week Overview' found")
    
        if not orange_callout_completion:
            errors.append("[X] Orange callout showing completion percentage not found")
        else:
            checks_passed.append("[C] Orange callout showing completion percentage found")
    
        if not h2_task_breakdown:
            errors.append("[X] heading_2 '📊 Task Breakdown' not found")
        else:
            checks_passed.append("[C] heading_2 '📊 Task Breakdown' found")
    
        if not h3_completed:
            errors.append("[X] heading_3 '✅ Completed This Week' not found")
        else:
            checks_passed.append("[C] heading_3 '✅ Completed This Week' found")
    
        if not h3_in_progress:
            errors.append("[X] heading_3 '🔄 In Progress' not found")
        else:
            checks_passed.append("[C] heading_3 '🔄 In Progress' found")
    
        if not h3_upcoming:
            errors.append("[X] heading_3 '📌 Upcoming Next Week' not found")
        else:
            checks_passed.append("[C] heading_3 '📌 Upcoming Next Week' found")
    
        if not h2_planning_tips:
            errors.append("[X] heading_2 '💡 Planning Tips' not found")
        else:
            checks_passed.append("[C] heading_2 '💡 Planning Tips' found")
    
        if not quote_tip:
            errors.append("[X] Quote block with planning tip not found")
        else:
            checks_passed.append("[C] Quote block with planning tip found")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: reorganize-company-handbook-complete-v2
# Description: Complete reorganization of Company Handbook with swapped sections,
# Communication Guidelines, and moved Work Policies
# =============================================================================
def _validate_agent_reorganize_company_handbook_complete(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate complete Company Handbook reorganization with:
    - Benefits section now appears where Our Values was (swapped)
    - Communication Guidelines heading_3 added after Time Off in Work Policies
    - Paragraph and 3 bulleted items under Communication Guidelines
    - Work Policies is now the first major section after introduction
    
    Returns 1.0 only if ALL requirements are met, otherwise 0.0
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Find Company Handbook page
    try:
        handbook_pages = _get_pages_by_filter(backend, {"title": "Company Handbook"})
        if not handbook_pages:
            errors.append("[X] Company Handbook page not found")
        else:
            checks_passed.append("[C] Company Handbook page found")
        handbook_page = handbook_pages[0]
    
        handbook_id = handbook_page.get("_id")
        page_blocks = _get_blocks_by_filter(backend, {"pageId": handbook_id})
    
        # 2. Track positions and elements
        intro_paragraph_idx = -1
        work_policies_idx = -1
        our_values_idx = -1
        benefits_idx = -1
        time_off_idx = -1
        comm_guidelines_idx = -1
    
        h3_communication_guidelines = False
        paragraph_async = False
        bulleted_slack = False
        bulleted_email = False
        bulleted_notion = False
    
        for idx, block in enumerate(page_blocks):
            block_type = block.get("type", "")
            block_content = block.get("content", "")
            content_lower = block_content.lower()
        
            # Find intro paragraph (typically first paragraph)
            if block_type == "paragraph" and idx < 5 and intro_paragraph_idx == -1:
                intro_paragraph_idx = idx
        
            if block_type == "heading2":
                if "work policies" in content_lower:
                    work_policies_idx = idx
                elif "our values" in content_lower:
                    our_values_idx = idx
                elif "benefits" in content_lower and "performance" not in content_lower:
                    benefits_idx = idx
        
            if block_type == "heading3":
                if "time off" in content_lower:
                    time_off_idx = idx
                if "communication guidelines" in content_lower:
                    h3_communication_guidelines = True
                    comm_guidelines_idx = idx
        
            if block_type == "paragraph" and "asynchronous communication" in content_lower:
                paragraph_async = True
        
            if block_type == "bulletedList":
                if "slack" in content_lower and "4 hours" in content_lower:
                    bulleted_slack = True
                if "email" in content_lower and "formal" in content_lower:
                    bulleted_email = True
                if "notion" in content_lower and "documentation" in content_lower:
                    bulleted_notion = True
    
        # Validate Work Policies is first major section after intro
        if work_policies_idx == -1:
            errors.append("[X] Work Policies section not found")
        else:
            checks_passed.append("[C] Work Policies section found")
    
        # Check Work Policies comes before Our Values and Benefits
        if our_values_idx != -1 and work_policies_idx > our_values_idx:
            errors.append("[X] Work Policies should be the first major section (before Our Values)")
        else:
            checks_passed.append("[C] Work Policies should be the first major section (before Our Values)")
    
        if benefits_idx != -1 and work_policies_idx > benefits_idx:
            errors.append("[X] Work Policies should be the first major section (before Benefits)")
        else:
            checks_passed.append("[C] Work Policies should be the first major section (before Benefits)")
    
        # Validate sections were swapped (Benefits before Our Values)
        if our_values_idx != -1 and benefits_idx != -1:
            if benefits_idx > our_values_idx:
                errors.append("[X] Benefits section should appear before Our Values after swap")
            else:
                checks_passed.append("[C] Benefits section should appear before Our Values after swap")
    
        if not h3_communication_guidelines:
            errors.append("[X] heading_3 'Communication Guidelines' not found")
        else:
            checks_passed.append("[C] heading_3 'Communication Guidelines' found")
    
        # Validate Communication Guidelines is after Time Off
        if time_off_idx != -1 and comm_guidelines_idx != -1:
            if comm_guidelines_idx < time_off_idx:
                errors.append("[X] Communication Guidelines should appear after Time Off")
            else:
                checks_passed.append("[C] Communication Guidelines should appear after Time Off")
    
        if not paragraph_async:
            errors.append("[X] Paragraph about asynchronous communication not found")
        else:
            checks_passed.append("[C] Paragraph about asynchronous communication found")
    
        if not bulleted_slack:
            errors.append("[X] Bulleted item about Slack with 4 hours response time not found")
        else:
            checks_passed.append("[C] Bulleted item about Slack with 4 hours response time found")
    
        if not bulleted_email:
            errors.append("[X] Bulleted item about Email for formal communications not found")
        else:
            checks_passed.append("[C] Bulleted item about Email for formal communications found")
    
        if not bulleted_notion:
            errors.append("[X] Bulleted item about Notion for documentation not found")
        else:
            checks_passed.append("[C] Bulleted item about Notion for documentation found")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: create-architecture-coverage-report-v2
# Description: Create an 'Architecture Documentation Coverage Report' as child 
# of 'Architecture' page analyzing entire architecture hierarchy
# =============================================================================
def _validate_agent_create_architecture_coverage_report(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate Architecture Documentation Coverage Report creation with:
    - Report is child of 'Architecture' page
    - Main heading_1 '🏗️ Architecture Documentation Coverage'
    - heading_2 '🌳 Documentation Tree' section with nested structure
    - For each architectural branch: heading_2/heading_3 showing sections
    - Callouts with coverage indicators (green >20, yellow 10-20, red <10 blocks)
    - Each callout has '📊' icon and '[Section]: [count] content blocks' format
    - Bulleted lists showing block type distribution
    - heading_2 '🎯 Gap Analysis' with numbered list of low-content sections
    - heading_2 '📋 Action Plan' with exactly 5 todo items
    
    Returns 1.0 only if ALL requirements are met, otherwise 0.0
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Find the 'Architecture' page
    try:
        architecture_pages = _get_pages_by_filter(backend, {"title": "Architecture"})
        if not architecture_pages:
            errors.append("[X] Architecture page not found")
        else:
            checks_passed.append("[C] Architecture page found")
        architecture_page = architecture_pages[0]
    
        # 2. Find the coverage report as child of Architecture
        child_pages = _get_pages_by_filter(backend, {"parentId": architecture_page.get("_id")})
        coverage_report = next((p for p in child_pages if "architecture documentation coverage report" in p.get("title", "").lower()), None)
        if not coverage_report:
            errors.append("[X] Architecture Documentation Coverage Report not found as child of Architecture page")
        else:
            checks_passed.append("[C] Architecture Documentation Coverage Report found as child of Architecture page")
    
        report_id = coverage_report.get("_id")
    
        # 3. Get all blocks for the report page
        report_blocks = _get_blocks_by_filter(backend, {"pageId": report_id})
    
        if len(report_blocks) < 10:
            errors.append(f"[X] Coverage report needs sufficient blocks (headings, callouts, lists, todos), found {len(report_blocks)}")
        else:
            checks_passed.append(f"[C] Coverage report needs sufficient blocks (headings, callouts, lists, todos), found {len(report_blocks)}")
    
        # 4. Find key structural elements
        main_heading_idx = -1
        doc_tree_heading_idx = -1
        gap_analysis_heading_idx = -1
        action_plan_heading_idx = -1
    
        coverage_callouts = []
        gap_analysis_items = []
        action_plan_todos = []
        block_distribution_lists = []
    
        for idx, block in enumerate(report_blocks):
            block_type = block.get("type", "")
            block_content = block.get("content", "")
            block_properties = block.get("properties", {})
        
            # Find main heading
            if block_type == "heading1" and "architecture documentation coverage" in block_content.lower():
                main_heading_idx = idx
        
            # Find Documentation Tree heading
            if block_type == "heading2" and "documentation tree" in block_content.lower():
                doc_tree_heading_idx = idx
        
            # Find Gap Analysis heading
            if block_type == "heading2" and "gap analysis" in block_content.lower():
                gap_analysis_heading_idx = idx
        
            # Find Action Plan heading
            if block_type == "heading2" and "action plan" in block_content.lower():
                action_plan_heading_idx = idx
        
            # Find coverage callouts with chart emoji
            if block_type == "callout":
                icon_prop = block_properties.get("icon", "") if isinstance(block_properties, dict) else ""
                icon_value = icon_prop.get("value", "") if isinstance(icon_prop, dict) else str(icon_prop)
            
                if "📊" in icon_value and "blocks" in block_content.lower():
                    bg_color = block_properties.get("backgroundColor", "") if isinstance(block_properties, dict) else ""
                    coverage_callouts.append({
                        "idx": idx,
                        "background": bg_color,
                        "content": block_content
                    })
        
            # Find numbered list items (for gap analysis)
            if block_type == "numberedList" and gap_analysis_heading_idx != -1 and idx > gap_analysis_heading_idx:
                if action_plan_heading_idx == -1 or idx < action_plan_heading_idx:
                    gap_analysis_items.append(idx)
        
            # Find todo blocks (for action plan)
            if block_type == "todo" and action_plan_heading_idx != -1 and idx > action_plan_heading_idx:
                action_plan_todos.append(idx)
        
            # Find bulleted lists with block type distribution
            if block_type == "bulletedList" and ("headings:" in block_content.lower() or 
                                                  "code examples:" in block_content.lower() or
                                                  "explanatory text:" in block_content.lower()):
                block_distribution_lists.append(idx)
    
        # 5. Validate main heading exists
        if main_heading_idx == -1:
            errors.append("[X] Main heading_1 '🏗️ Architecture Documentation Coverage' not found")
        else:
            checks_passed.append("[C] Main heading_1 '🏗️ Architecture Documentation Coverage' found")
    
        # 6. Validate Documentation Tree section exists
        if doc_tree_heading_idx == -1:
            errors.append("[X] heading_2 '🌳 Documentation Tree' not found")
        else:
            checks_passed.append("[C] heading_2 '🌳 Documentation Tree' found")
    
        # 7. Validate coverage callouts exist (should have at least 3 for different sections)
        if len(coverage_callouts) < 3:
            errors.append(f"[X] Expected at least 3 coverage indicator callouts with 📊 icon, found {len(coverage_callouts)}")
        else:
            checks_passed.append(f"[C] Found at least 3 coverage indicator callouts with 📊 icon ({len(coverage_callouts)})")
    
        # 8. Validate callouts have correct color coding
        has_green = any("green" in c["background"].lower() for c in coverage_callouts)
        has_yellow = any("yellow" in c["background"].lower() for c in coverage_callouts)
        has_red = any("red" in c["background"].lower() for c in coverage_callouts)
    
        if not (has_green or has_yellow or has_red):
            errors.append("[X] Coverage callouts should use green (>20 blocks), yellow (10-20), or red (<10) backgrounds")
        else:
            checks_passed.append("[C] Coverage callouts should use green (>20 blocks), yellow (10-20), or red (<10) backgrounds")
    
        # 9. Validate block type distribution lists exist
        if len(block_distribution_lists) < 2:
            errors.append(f"[X] Expected bulleted lists showing block type distributions, found {len(block_distribution_lists)}")
        else:
            checks_passed.append(f"[C] Expected bulleted lists showing block type distributions, found {len(block_distribution_lists)}")
    
        # 10. Validate Gap Analysis section
        if gap_analysis_heading_idx == -1:
            errors.append("[X] heading_2 '🎯 Gap Analysis' not found")
        else:
            checks_passed.append("[C] heading_2 '🎯 Gap Analysis' found")
    
        if len(gap_analysis_items) < 1:
            errors.append("[X] Gap Analysis section should contain numbered list of sections needing more documentation")
        else:
            checks_passed.append("[C] Gap Analysis section should contain numbered list of sections needing more documentation")
    
        # 11. Validate Action Plan section with exactly 5 todos
        if action_plan_heading_idx == -1:
            errors.append("[X] heading_2 '📋 Action Plan' not found")
        else:
            checks_passed.append("[C] heading_2 '📋 Action Plan' found")
    
        if len(action_plan_todos) != 5:
            errors.append(f"[X] Action Plan should contain exactly 5 todo items for improving documentation, found {len(action_plan_todos)}")
        else:
            checks_passed.append(f"[C] Action Plan should contain exactly 5 todo items for improving documentation, found {len(action_plan_todos)}")
    
        # ALL requirements met!
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: create-quarterly-report-summary-v2
# Description: Create 'Quarterly Report Summary' under Company Handbook
# aggregating data from Q1/Q2 Goals and Bug Tracker
# =============================================================================
def _validate_agent_create_quarterly_report_summary(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate Quarterly Report Summary creation with:
    - Summary page exists under Company Handbook
    - heading_1 '📈 Quarterly Report Summary'
    - heading_2 '🎯 Q1 & Q2 Objectives Analysis'
    - Paragraph with 'Report generated: [TODAY'S DATE]'
    - Comparison table using numbered lists showing:
      * Q1 Goals: 3 objectives, 66.7% complete
      * Q2 Goals: 2 objectives, 0% complete
      * Total Roadmap Progress: 2 of 5 (40%)
    - heading_2 '🐛 Bug Resolution Status' 
    - Bug stats: Critical: 50% resolved, Overall: 5 total, 2 resolved
    
    Returns 1.0 only if ALL requirements are met, otherwise 0.0
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Find the Company Handbook page
    try:
        handbook_pages = _get_pages_by_filter(backend, {"title": "Company Handbook"})
        if not handbook_pages:
            errors.append("[X] Company Handbook page not found")
        else:
            checks_passed.append("[C] Company Handbook page found")
        handbook_page = handbook_pages[0]
    
        # 2. Find the Quarterly Report Summary as child
        child_pages = _get_pages_by_filter(backend, {"parentId": handbook_page.get("_id")})
        summary_page = next((p for p in child_pages if "quarterly report summary" in p.get("title", "").lower()), None)
        if not summary_page:
            errors.append("[X] Quarterly Report Summary not found as child of Company Handbook")
        else:
            checks_passed.append("[C] Quarterly Report Summary found as child of Company Handbook")
    
        summary_id = summary_page.get("_id")
    
        # 3. Get all blocks for the summary page
        summary_blocks = _get_blocks_by_filter(backend, {"pageId": summary_id})
    
        if len(summary_blocks) < 6:
            errors.append(f"[X] Quarterly Report Summary needs sufficient blocks, found {len(summary_blocks)}")
        else:
            checks_passed.append(f"[C] Quarterly Report Summary needs sufficient blocks, found {len(summary_blocks)}")
    
        # 4. Find key structural elements
        main_heading_idx = -1
        objectives_heading_idx = -1
        bug_heading_idx = -1
        date_paragraph_idx = -1
    
        q1_data_found = False
        q2_data_found = False
        total_progress_found = False
        bug_critical_found = False
        bug_overall_found = False
    
        for idx, block in enumerate(summary_blocks):
            block_type = block.get("type", "")
            block_content = block.get("content", "")
        
            # Find main heading
            if block_type == "heading1" and "quarterly report summary" in block_content.lower():
                main_heading_idx = idx
        
            # Find Q1 & Q2 Objectives Analysis heading
            if block_type == "heading2" and "q1" in block_content.lower() and "q2" in block_content.lower() and "objectives" in block_content.lower():
                objectives_heading_idx = idx
        
            # Find Bug Resolution Status heading
            if block_type == "heading2" and "bug resolution" in block_content.lower():
                bug_heading_idx = idx
        
            # Find date paragraph
            if block_type == "paragraph" and "report generated:" in block_content.lower():
                date_paragraph_idx = idx
        
            # Check for Q1 data (3 objectives, 66.7% or 67%)
            if ("q1" in block_content.lower() and "3" in block_content and 
                ("66.7" in block_content or "67" in block_content)):
                q1_data_found = True
        
            # Check for Q2 data (2 objectives, 0%)
            if ("q2" in block_content.lower() and "2" in block_content and 
                "0" in block_content and "%" in block_content):
                q2_data_found = True
        
            # Check for total progress (2 of 5, 40%)
            if ("total" in block_content.lower() and "2" in block_content and 
                "5" in block_content and "40" in block_content):
                total_progress_found = True
        
            # Check for critical bug resolution (50%)
            if ("critical" in block_content.lower() and "50" in block_content and 
                "%" in block_content):
                bug_critical_found = True
        
            # Check for overall bug count (5 total, 2 resolved)
            if ("5" in block_content and "2" in block_content and 
                ("total" in block_content.lower() or "resolved" in block_content.lower())):
                bug_overall_found = True
    
        # 5. Validate main heading
        if main_heading_idx == -1:
            errors.append("[X] Main heading_1 '📈 Quarterly Report Summary' not found")
        else:
            checks_passed.append("[C] Main heading_1 '📈 Quarterly Report Summary' found")
    
        # 6. Validate Objectives Analysis heading
        if objectives_heading_idx == -1:
            errors.append("[X] heading_2 '🎯 Q1 & Q2 Objectives Analysis' not found")
        else:
            checks_passed.append("[C] heading_2 '🎯 Q1 & Q2 Objectives Analysis' found")
    
        # 7. Validate date paragraph
        if date_paragraph_idx == -1:
            errors.append("[X] Paragraph with 'Report generated: [date]' not found")
        else:
            checks_passed.append("[C] Paragraph with 'Report generated: [date]' found")
    
        # 8. Validate Q1 data
        if not q1_data_found:
            errors.append("[X] Q1 Goals data incorrect or missing (should show 3 objectives, 66.7% complete)")
        else:
            checks_passed.append("[C] Q1 Goals data incorrect or has (should show 3 objectives, 66.7% complete)")
    
        # 9. Validate Q2 data
        if not q2_data_found:
            errors.append("[X] Q2 Goals data incorrect or missing (should show 2 objectives, 0% complete)")
        else:
            checks_passed.append("[C] Q2 Goals data incorrect or has (should show 2 objectives, 0% complete)")
    
        # 10. Validate total progress
        if not total_progress_found:
            errors.append("[X] Total Roadmap Progress incorrect or missing (should show 2 of 5, 40%)")
        else:
            checks_passed.append("[C] Total Roadmap Progress incorrect or has (should show 2 of 5, 40%)")
    
        # 11. Validate Bug Resolution heading
        if bug_heading_idx == -1:
            errors.append("[X] heading_2 '🐛 Bug Resolution Status' not found")
        else:
            checks_passed.append("[C] heading_2 '🐛 Bug Resolution Status' found")
    
        # 12. Validate critical bug stats
        if not bug_critical_found:
            errors.append("[X] Critical Issues resolution incorrect or missing (should show 50% resolved)")
        else:
            checks_passed.append("[C] Critical Issues resolution incorrect or has (should show 50% resolved)")
    
        # 13. Validate overall bug stats
        if not bug_overall_found:
            errors.append("[X] Overall Bug Count incorrect or missing (should show 5 total, 2 resolved)")
        else:
            checks_passed.append("[C] Overall Bug Count incorrect or has (should show 5 total, 2 resolved)")
    
        # ALL requirements met!
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: add-implementation-roadmap-to-feature-requests-v2
# Description: On Feature Requests page, add Implementation Roadmap grouping
# todos into Q1/Q2/Future releases with callouts
# =============================================================================
def _validate_agent_add_implementation_roadmap_to_feature_requests(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate Implementation Roadmap addition to Feature Requests with:
    - heading_2 '🔄 Implementation Roadmap' at top of page
    - Three sections with heading_3: '🚀 Q1 2025 Release', '🎯 Q2 2025 Release', '📅 Future Releases'
    - Todos distributed evenly across quarters (±1 if not divisible by 3)
    - Each section has paragraph 'Target release: [date]' (March 31, June 30, or TBD)
    - Each section has callout: Q1 green with '💚 [X] features planned', 
      Q2 blue with '💙 [X] features planned', Future gray with '🔮 [X] features in backlog'
    - Divider at end
    - Quote block with exact text 'Innovation distinguishes between a leader and a follower. - Steve Jobs'
    
    Returns 1.0 only if ALL requirements are met, otherwise 0.0
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Find the Feature Requests page
    try:
        feature_requests_pages = _get_pages_by_filter(backend, {"title": "Feature Requests"})
        if not feature_requests_pages:
            errors.append("[X] Feature Requests page not found")
        else:
            checks_passed.append("[C] Feature Requests page found")
        feature_requests_page = feature_requests_pages[0]
    
        fr_id = feature_requests_page.get("_id")
    
        # 2. Get all blocks for the page
        fr_blocks = _get_blocks_by_filter(backend, {"pageId": fr_id})
    
        if len(fr_blocks) < 10:
            errors.append(f"[X] Feature Requests page needs sufficient blocks for roadmap structure, found {len(fr_blocks)}")
        else:
            checks_passed.append(f"[C] Feature Requests page needs sufficient blocks for roadmap structure, found {len(fr_blocks)}")
    
        # 3. Find key structural elements
        roadmap_heading_idx = -1
        q1_heading_idx = -1
        q2_heading_idx = -1
        future_heading_idx = -1
    
        q1_target_paragraph = None
        q2_target_paragraph = None
        future_target_paragraph = None
    
        q1_callout = None
        q2_callout = None
        future_callout = None
    
        divider_found = False
        quote_found = False
    
        for idx, block in enumerate(fr_blocks):
            block_type = block.get("type", "")
            block_content = block.get("content", "")
            block_properties = block.get("properties", {})
        
            # Find Implementation Roadmap heading
            if block_type == "heading2" and "implementation roadmap" in block_content.lower():
                roadmap_heading_idx = idx
        
            # Find Q1 heading
            if block_type == "heading3" and "q1 2025" in block_content.lower():
                q1_heading_idx = idx
        
            # Find Q2 heading
            if block_type == "heading3" and "q2 2025" in block_content.lower():
                q2_heading_idx = idx
        
            # Find Future heading
            if block_type == "heading3" and "future releases" in block_content.lower():
                future_heading_idx = idx
        
            # Find target paragraphs
            if block_type == "paragraph" and "target release:" in block_content.lower():
                if "march 31" in block_content.lower() or "march" in block_content.lower():
                    q1_target_paragraph = block_content
                elif "june 30" in block_content.lower() or "june" in block_content.lower():
                    q2_target_paragraph = block_content
                elif "tbd" in block_content.lower():
                    future_target_paragraph = block_content
        
            # Find callouts
            if block_type == "callout":
                bg_color = block_properties.get("backgroundColor", "") if isinstance(block_properties, dict) else ""
            
                if "green" in bg_color.lower() and "💚" in block_content and "features planned" in block_content.lower():
                    q1_callout = block_content
                elif "blue" in bg_color.lower() and "💙" in block_content and "features planned" in block_content.lower():
                    q2_callout = block_content
                elif "gray" in bg_color.lower() and "🔮" in block_content and "features in backlog" in block_content.lower():
                    future_callout = block_content
        
            # Find divider
            if block_type == "divider":
                divider_found = True
        
            # Find quote with Steve Jobs
            if block_type == "quote" and "innovation" in block_content.lower() and "steve jobs" in block_content.lower():
                quote_found = True
    
        # 4. Validate roadmap heading at top
        if roadmap_heading_idx == -1:
            errors.append("[X] heading_2 '🔄 Implementation Roadmap' not found")
        else:
            checks_passed.append("[C] heading_2 '🔄 Implementation Roadmap' found")
    
        # Check it's near the top (first few blocks)
        if roadmap_heading_idx > 3:
            errors.append(f"[X] Implementation Roadmap should be at top of page, found at index {roadmap_heading_idx}")
        else:
            checks_passed.append(f"[C] Implementation Roadmap should be at top of page, found at index {roadmap_heading_idx}")
    
        # 5. Validate three quarter headings
        if q1_heading_idx == -1:
            errors.append("[X] heading_3 '🚀 Q1 2025 Release' not found")
        else:
            checks_passed.append("[C] heading_3 '🚀 Q1 2025 Release' found")
    
        if q2_heading_idx == -1:
            errors.append("[X] heading_3 '🎯 Q2 2025 Release' not found")
        else:
            checks_passed.append("[C] heading_3 '🎯 Q2 2025 Release' found")
    
        if future_heading_idx == -1:
            errors.append("[X] heading_3 '📅 Future Releases' not found")
        else:
            checks_passed.append("[C] heading_3 '📅 Future Releases' found")
    
        # 6. Validate target release paragraphs
        if not q1_target_paragraph:
            errors.append("[X] Q1 section missing 'Target release: March 31' paragraph")
        else:
            checks_passed.append("[C] Q1 section has 'Target release: March 31' paragraph")
    
        if not q2_target_paragraph:
            errors.append("[X] Q2 section missing 'Target release: June 30' paragraph")
        else:
            checks_passed.append("[C] Q2 section has 'Target release: June 30' paragraph")
    
        if not future_target_paragraph:
            errors.append("[X] Future section missing 'Target release: TBD' paragraph")
        else:
            checks_passed.append("[C] Future section has 'Target release: TBD' paragraph")
    
        # 7. Validate callouts with correct colors and emojis
        if not q1_callout:
            errors.append("[X] Q1 section missing green callout with '💚 [X] features planned'")
        else:
            checks_passed.append("[C] Q1 section has green callout with '💚 [X] features planned'")
    
        if not q2_callout:
            errors.append("[X] Q2 section missing blue callout with '💙 [X] features planned'")
        else:
            checks_passed.append("[C] Q2 section has blue callout with '💙 [X] features planned'")
    
        if not future_callout:
            errors.append("[X] Future section missing gray callout with '🔮 [X] features in backlog'")
        else:
            checks_passed.append("[C] Future section has gray callout with '🔮 [X] features in backlog'")
    
        # 8. Validate divider
        if not divider_found:
            errors.append("[X] Divider block not found at end")
        else:
            checks_passed.append("[C] Divider block found at end")
    
        # 9. Validate quote
        if not quote_found:
            errors.append("[X] Quote block with 'Innovation distinguishes between a leader and a follower. - Steve Jobs' not found")
        else:
            checks_passed.append("[C] Quote block with 'Innovation distinguishes between a leader and a follower. - Steve Jobs' found")
    
        # ALL requirements met!
        # TODO: Could validate todo distribution across quarters, but complex without knowing original todo count
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: add-quick-start-checklist-to-onboarding-v2
# Description: Add Quick Start Checklist section to Onboarding Guide with
# 6 unchecked todos and total block count
# =============================================================================
def _validate_agent_add_quick_start_checklist_to_onboarding(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate Quick Start Checklist addition to Onboarding Guide with:
    - heading_2 '🚀 Quick Start Checklist' appears after main heading but before other content
    - Yellow callout with '⏱️' icon containing 'Estimated completion time: 45 minutes'
    - Exactly 6 unchecked todo blocks with specific texts:
      * '📧 Verify your email and enable 2FA'
      * '👤 Complete your profile information'
      * '🔑 Generate and save your API keys'
      * '📚 Read the company handbook'
      * '💬 Join the team Slack channels'
      * '📅 Schedule 1-on-1 with your manager'
    - Paragraph with 'This page contains [X] total blocks to help you get started'
    
    NOTE: Italics formatting mentioned but not validated (implementation later)
    
    Returns 1.0 only if ALL requirements are met, otherwise 0.0
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Find the Onboarding Guide page
    try:
        onboarding_pages = _get_pages_by_filter(backend, {"title": "Onboarding Guide"})
        if not onboarding_pages:
            errors.append("[X] Onboarding Guide page not found")
        else:
            checks_passed.append("[C] Onboarding Guide page found")
        onboarding_page = onboarding_pages[0]
    
        onboarding_id = onboarding_page.get("_id")
    
        # 2. Get all blocks for the page
        onboarding_blocks = _get_blocks_by_filter(backend, {"pageId": onboarding_id})
    
        if len(onboarding_blocks) < 9:
            errors.append(f"[X] Onboarding Guide needs at least 9 new blocks (heading, callout, 6 todos, paragraph), found {len(onboarding_blocks)}")
        else:
            checks_passed.append(f"[C] Onboarding Guide needs at least 9 new blocks (heading, callout, 6 todos, paragraph), found {len(onboarding_blocks)}")
    
        # 3. Find key elements
        quick_start_heading_idx = -1
        yellow_callout_idx = -1
        block_count_paragraph_idx = -1
    
        expected_todos = [
            "verify your email and enable 2fa",
            "complete your profile information",
            "generate and save your api keys",
            "read the company handbook",
            "join the team slack channels",
            "schedule 1-on-1 with your manager"
        ]
        found_todos = []
    
        for idx, block in enumerate(onboarding_blocks):
            block_type = block.get("type", "")
            block_content = block.get("content", "")
            block_properties = block.get("properties", {})
        
            # Find Quick Start Checklist heading
            if block_type == "heading2" and "quick start checklist" in block_content.lower():
                quick_start_heading_idx = idx
        
            # Find yellow callout with timer emoji
            if block_type == "callout":
                bg_color = block_properties.get("backgroundColor", "") if isinstance(block_properties, dict) else ""
                icon_prop = block_properties.get("icon", "") if isinstance(block_properties, dict) else ""
                icon_value = icon_prop.get("value", "") if isinstance(icon_prop, dict) else str(icon_prop)
            
                if ("yellow" in bg_color.lower() and "⏱️" in icon_value and 
                    "45 minutes" in block_content.lower()):
                    yellow_callout_idx = idx
        
            # Find todos
            if block_type == "todo":
                content_lower = block_content.lower()
                for expected_todo in expected_todos:
                    if expected_todo in content_lower:
                        # Check if unchecked
                        is_checked = block_properties.get("checked", False) if isinstance(block_properties, dict) else False
                        found_todos.append({
                            "idx": idx,
                            "content": block_content,
                            "checked": is_checked,
                            "expected": expected_todo
                        })
                        break
        
            # Find block count paragraph
            # TODO: Check for italic formatting (implement later)
            if block_type == "paragraph" and "this page contains" in block_content.lower() and "total blocks" in block_content.lower():
                block_count_paragraph_idx = idx
    
        # 4. Validate heading exists and is near top
        if quick_start_heading_idx == -1:
            errors.append("[X] heading_2 '🚀 Quick Start Checklist' not found")
        else:
            checks_passed.append("[C] heading_2 '🚀 Quick Start Checklist' found")
    
        if quick_start_heading_idx > 2:
            errors.append(f"[X] Quick Start Checklist should appear near top (after main heading), found at index {quick_start_heading_idx}")
        else:
            checks_passed.append(f"[C] Quick Start Checklist should appear near top (after main heading), found at index {quick_start_heading_idx}")
    
        # 5. Validate yellow callout
        if yellow_callout_idx == -1:
            errors.append("[X] Yellow callout with ⏱️ icon and '45 minutes' not found")
        else:
            checks_passed.append("[C] Yellow callout with ⏱️ icon and '45 minutes' found")
    
        if yellow_callout_idx <= quick_start_heading_idx:
            errors.append("[X] Yellow callout should appear after Quick Start Checklist heading")
        else:
            checks_passed.append("[C] Yellow callout should appear after Quick Start Checklist heading")
    
        # 6. Validate 6 todos
        if len(found_todos) != 6:
            missing = [exp for exp in expected_todos if not any(ft["expected"] == exp for ft in found_todos)]
            errors.append(f"[X] Expected 6 specific todos, found {len(found_todos)}. Missing: {missing[:2] if missing else 'unknown'}")
        else:
            checks_passed.append(f"[C] Found 6 specific todos as expected")
    
        # 7. Check all todos are unchecked
        checked_todos = [ft for ft in found_todos if ft["checked"]]
        if checked_todos:
            errors.append(f"[X] All todos should be unchecked, found {len(checked_todos)} checked todos")
        else:
            checks_passed.append(f"[C] All todos should be unchecked, found {len(checked_todos)} checked todos")
    
        # 8. Validate block count paragraph
        if block_count_paragraph_idx == -1:
            errors.append("[X] Paragraph with 'This page contains [X] total blocks to help you get started' not found")
        else:
            checks_passed.append("[C] Paragraph with 'This page contains [X] total blocks to help you get started' found")
    
        # Verify paragraph comes after todos
        last_todo_idx = max(ft["idx"] for ft in found_todos)
        if block_count_paragraph_idx <= last_todo_idx:
            errors.append("[X] Block count paragraph should appear after all todos")
        else:
            checks_passed.append("[C] Block count paragraph should appear after all todos")
    
        # 9. Extract and validate block count
        block_count_block = onboarding_blocks[block_count_paragraph_idx]
        block_count_content = block_count_block.get("content", "")
    
        # Check if count is reasonable (should match actual total blocks)
        total_blocks = len(onboarding_blocks)
        if str(total_blocks) not in block_count_content:
            errors.append(f"[X] Block count in paragraph should be {total_blocks}, but paragraph content is: '{block_count_content}'")
        else:
            checks_passed.append(f"[C] Block count in paragraph should be {total_blocks}, but paragraph content is: '{block_count_content}'")
    
        # ALL requirements met!
        # TODO: Validate italic formatting when implemented
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: add-progressive-disclosure-to-onboarding-v2
# Description: Add progressive disclosure system with 3 modules to Onboarding Guide
# with colored callouts, quotes, and congratulations callout
# =============================================================================
def _validate_agent_add_progressive_disclosure_to_onboarding(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate progressive disclosure system addition to Onboarding Guide with:
    - heading_2 '🎓 Onboarding Modules' after main content
    - Three modules with heading_3: '📘 Module 1: Basics', '📗 Module 2: Intermediate', '📕 Module 3: Advanced'
    - Each module has a TOGGLE block (expandable section) with specific color (blue, green, red)
    - Each module has 5 numbered list items with appropriate difficulty tasks (inside toggle or after)
    - Dividers and contextually appropriate quotes between modules
    - Final unchecked todo: '[ ] Complete all three onboarding modules'
    - Final purple callout with 🎉 icon: 'Congratulations on completing the structured onboarding program!'
    
    NOTE: This task requires toggle blocks which is not yet implemented.
    
    Returns 1.0 only if ALL requirements are met, otherwise 0.0
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Find the Onboarding Guide page
    try:
        onboarding_page = _find_page_by_title(final_state_backend, "Onboarding Guide")
        if not onboarding_page:
            errors.append("[X] Onboarding Guide page not found")
        else:
            checks_passed.append("[C] Onboarding Guide page found")
    
        onboarding_id = onboarding_page.get("_id")
    
        # 2. Get all blocks for the page
        onboarding_blocks = _get_blocks_for_page(final_state_backend, onboarding_id)
    
        if len(onboarding_blocks) < 20:
            errors.append(f"[X] Onboarding Guide needs many blocks for 3 modules with content, found {len(onboarding_blocks)}")
        else:
            checks_passed.append(f"[C] Onboarding Guide needs many blocks for 3 modules with content, found {len(onboarding_blocks)}")
    
        # 3. Find key elements
        modules_heading_idx = -1
        module1_heading_idx = -1
        module2_heading_idx = -1
        module3_heading_idx = -1
    
        # Look for toggle blocks specifically (not callouts)
        module1_toggle = None
        module2_toggle = None
        module3_toggle = None
    
        module1_tasks = []
        module2_tasks = []
        module3_tasks = []
    
        dividers_found = 0
        quotes_found = 0
    
        final_todo_idx = -1
        purple_callout_idx = -1
    
        for idx, block in enumerate(onboarding_blocks):
            block_type = block.get("type", "")
            block_content = block.get("content", "")
            block_properties = block.get("properties", {})
        
            # Find Onboarding Modules heading
            if block_type == "heading2" and "onboarding modules" in block_content.lower():
                modules_heading_idx = idx
        
            # Find module headings
            if block_type == "heading3":
                if "module 1" in block_content.lower() and "basics" in block_content.lower():
                    module1_heading_idx = idx
                elif "module 2" in block_content.lower() and "intermediate" in block_content.lower():
                    module2_heading_idx = idx
                elif "module 3" in block_content.lower() and "advanced" in block_content.lower():
                    module3_heading_idx = idx
        
            # Find toggle blocks (expandable sections) - NOT callouts
            # Toggle blocks are the proper way to implement "expandable sections" in Notion
            if block_type == "toggle":
                bg_color = block_properties.get("backgroundColor", "") if isinstance(block_properties, dict) else ""
            
                # Assign toggle to module based on position relative to headings
                if module1_heading_idx != -1 and module1_heading_idx < idx:
                    if module2_heading_idx == -1 or idx < module2_heading_idx:
                        if "blue" in bg_color.lower() or not module1_toggle:
                            module1_toggle = {"idx": idx, "color": bg_color}
                if module2_heading_idx != -1 and module2_heading_idx < idx:
                    if module3_heading_idx == -1 or idx < module3_heading_idx:
                        if "green" in bg_color.lower() or not module2_toggle:
                            module2_toggle = {"idx": idx, "color": bg_color}
                if module3_heading_idx != -1 and module3_heading_idx < idx:
                    if "red" in bg_color.lower() or not module3_toggle:
                        module3_toggle = {"idx": idx, "color": bg_color}
        
            # Find numbered lists for modules
            if block_type == "numberedList":
                # Determine which module this belongs to based on position
                if module1_heading_idx != -1 and module1_heading_idx < idx:
                    if module2_heading_idx == -1 or idx < module2_heading_idx:
                        module1_tasks.append(idx)
                if module2_heading_idx != -1 and module2_heading_idx < idx:
                    if module3_heading_idx == -1 or idx < module3_heading_idx:
                        module2_tasks.append(idx)
                if module3_heading_idx != -1 and module3_heading_idx < idx:
                    module3_tasks.append(idx)
        
            # Count dividers (should be between modules)
            if block_type == "divider":
                dividers_found += 1
        
            # Count quotes (should be between modules with wisdom)
            if block_type == "quote":
                quotes_found += 1
        
            # Find final todo
            if block_type == "todo" and "complete all three" in block_content.lower() and "modules" in block_content.lower():
                final_todo_idx = idx
        
            # Find purple congratulations callout (this is fine as a callout, not a toggle)
            if block_type == "callout":
                bg_color = block_properties.get("backgroundColor", "") if isinstance(block_properties, dict) else ""
                icon_prop = block_properties.get("icon", "") if isinstance(block_properties, dict) else ""
                icon_value = icon_prop.get("value", "") if isinstance(icon_prop, dict) else str(icon_prop)
            
                if ("purple" in bg_color.lower() and "🎉" in icon_value and 
                    "congratulations" in block_content.lower() and "onboarding program" in block_content.lower()):
                    purple_callout_idx = idx
    
        # 4. Validate Onboarding Modules heading
        if modules_heading_idx == -1:
            errors.append("[X] heading_2 '🎓 Onboarding Modules' not found")
        else:
            checks_passed.append("[C] heading_2 '🎓 Onboarding Modules' found")
    
        # 5. Validate three module headings with exact emojis
        if module1_heading_idx == -1:
            errors.append("[X] heading_3 '📘 Module 1: Basics' not found")
        else:
            checks_passed.append("[C] heading_3 '📘 Module 1: Basics' found")
    
        if module2_heading_idx == -1:
            errors.append("[X] heading_3 '📗 Module 2: Intermediate' not found")
        else:
            checks_passed.append("[C] heading_3 '📗 Module 2: Intermediate' found")
    
        if module3_heading_idx == -1:
            errors.append("[X] heading_3 '📕 Module 3: Advanced' not found")
        else:
            checks_passed.append("[C] heading_3 '📕 Module 3: Advanced' found")
    
        # 6. Validate module TOGGLE blocks (expandable sections) - NOT callouts
        # The task specifically asks for "expandable sections" which are toggle blocks in Notion
        if not module1_toggle:
            errors.append("[X] Module 1 missing toggle block (expandable section). Toggle blocks are required for progressive disclosure - callouts are not expandable.")
        else:
            checks_passed.append("[C] Module 1 has toggle block (expandable section). Toggle blocks are required for progressive disclosure - callouts are expandable.")
    
        if not module2_toggle:
            errors.append("[X] Module 2 missing toggle block (expandable section). Toggle blocks are required for progressive disclosure - callouts are not expandable.")
        else:
            checks_passed.append("[C] Module 2 has toggle block (expandable section). Toggle blocks are required for progressive disclosure - callouts are expandable.")
    
        if not module3_toggle:
            errors.append("[X] Module 3 missing toggle block (expandable section). Toggle blocks are required for progressive disclosure - callouts are not expandable.")
        else:
            checks_passed.append("[C] Module 3 has toggle block (expandable section). Toggle blocks are required for progressive disclosure - callouts are expandable.")
    
        # 7. Validate each module has 5 numbered tasks
        if len(module1_tasks) != 5:
            errors.append(f"[X] Module 1 should have exactly 5 numbered list items, found {len(module1_tasks)}")
        else:
            checks_passed.append(f"[C] Module 1 should have exactly 5 numbered list items, found {len(module1_tasks)}")
    
        if len(module2_tasks) != 5:
            errors.append(f"[X] Module 2 should have exactly 5 numbered list items, found {len(module2_tasks)}")
        else:
            checks_passed.append(f"[C] Module 2 should have exactly 5 numbered list items, found {len(module2_tasks)}")
    
        if len(module3_tasks) != 5:
            errors.append(f"[X] Module 3 should have exactly 5 numbered list items, found {len(module3_tasks)}")
        else:
            checks_passed.append(f"[C] Module 3 should have exactly 5 numbered list items, found {len(module3_tasks)}")
    
        # 8. Validate dividers between modules (should be at least 2)
        if dividers_found < 2:
            errors.append(f"[X] Expected dividers between modules, found {dividers_found}")
        else:
            checks_passed.append(f"[C] Expected dividers between modules, found {dividers_found}")
    
        # 9. Validate quotes between modules (should be at least 2)
        if quotes_found < 2:
            errors.append(f"[X] Expected contextually appropriate quotes between modules, found {quotes_found}")
        else:
            checks_passed.append(f"[C] Expected contextually appropriate quotes between modules, found {quotes_found}")
    
        # 10. Validate final todo
        if final_todo_idx == -1:
            errors.append("[X] Final todo '[ ] Complete all three onboarding modules' not found")
        else:
            checks_passed.append("[C] Final todo '[ ] Complete all three onboarding modules' found")
    
        # 11. Validate purple congratulations callout
        if purple_callout_idx == -1:
            errors.append("[X] Final purple callout with 🎉 icon and congratulations message not found")
        else:
            checks_passed.append("[C] Final purple callout with 🎉 icon and congratulations message found")
    
        # 12. Validate order (todo and callout should be at end)
        if final_todo_idx >= purple_callout_idx:
            errors.append("[X] Purple congratulations callout should appear after the final todo")
        else:
            checks_passed.append("[C] Purple congratulations callout should appear after the final todo")
    
        # ALL requirements met!
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: audit-project-documentation-comprehensive-v2
# Description: Comprehensive audit of Project Documentation and sub-pages with
# overview, related pages links, and review callout
# =============================================================================
def _validate_agent_audit_project_documentation_comprehensive(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate comprehensive Project Documentation audit with:
    - Main 'Project Documentation' page has heading_2 '📑 Documentation Overview' at top
    - Bulleted list showing each sub-page with icon and heading_2 count
    - 'Frontend Architecture' page has heading_2 '🔗 Related Pages' at end
    - Two bookmark blocks linking to 'Component Library' and 'State Management'
    - 'Engineering Wiki' page has yellow callout after first paragraph with review dates
      'Last reviewed: February 2024. Next review due: May 2024.'
    
    Returns 1.0 only if ALL requirements are met, otherwise 0.0
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Find the Project Documentation page
    try:
        proj_doc_pages = _get_pages_by_filter(backend, {"title": "Project Documentation"})
        if not proj_doc_pages:
            errors.append("[X] Project Documentation page not found")
        else:
            checks_passed.append("[C] Project Documentation page found")
        proj_doc_page = proj_doc_pages[0]
    
        proj_doc_id = proj_doc_page.get("_id")
        proj_doc_blocks = _get_blocks_by_filter(backend, {"pageId": proj_doc_id})
    
        # 2. Validate Documentation Overview section at top
        overview_heading_idx = -1
        bulleted_subpages = []
    
        for idx, block in enumerate(proj_doc_blocks):
            block_type = block.get("type", "")
            block_content = block.get("content", "")
        
            if block_type == "heading2" and "documentation overview" in block_content.lower():
                overview_heading_idx = idx
        
            # Find bulleted lists after overview heading
            if block_type == "bulletedList" and overview_heading_idx != -1 and idx > overview_heading_idx:
                # Check if it mentions sub-pages (Architecture, Frontend, etc.)
                if ("architecture" in block_content.lower() or "frontend" in block_content.lower() or
                    "backend" in block_content.lower() or "component" in block_content.lower()):
                    bulleted_subpages.append(block_content)
    
        if overview_heading_idx == -1:
            errors.append("[X] heading_2 '📑 Documentation Overview' not found at top of Project Documentation")
        else:
            checks_passed.append("[C] heading_2 '📑 Documentation Overview' found at top of Project Documentation")
    
        if overview_heading_idx > 2:
            errors.append(f"[X] Documentation Overview should be at top (after main heading), found at index {overview_heading_idx}")
        else:
            checks_passed.append(f"[C] Documentation Overview should be at top (after main heading), found at index {overview_heading_idx}")
    
        if len(bulleted_subpages) < 2:
            errors.append(f"[X] Expected bulleted list showing sub-pages with icons and section counts, found {len(bulleted_subpages)} items")
        else:
            checks_passed.append(f"[C] Expected bulleted list showing sub-pages with icons and section counts, found {len(bulleted_subpages)} items")
    
        # 3. Find Frontend Architecture page
        frontend_arch_pages = _get_pages_by_filter(backend, {"title": "Frontend Architecture"})
        if not frontend_arch_pages:
            errors.append("[X] Frontend Architecture page not found")
        else:
            checks_passed.append("[C] Frontend Architecture page found")
        frontend_arch_page = frontend_arch_pages[0]
    
        frontend_id = frontend_arch_page.get("_id")
        frontend_blocks = _get_blocks_by_filter(backend, {"pageId": frontend_id})
    
        # 4. Validate Related Pages section at end
        related_pages_heading_idx = -1
        bookmark_blocks = []
    
        for idx, block in enumerate(frontend_blocks):
            block_type = block.get("type", "")
            block_content = block.get("content", "")
        
            if block_type == "heading2" and "related pages" in block_content.lower():
                related_pages_heading_idx = idx
        
            if block_type == "bookmark":
                bookmark_blocks.append({
                    "idx": idx,
                    "content": block_content
                })
    
        if related_pages_heading_idx == -1:
            errors.append("[X] heading_2 '🔗 Related Pages' not found at end of Frontend Architecture")
        else:
            checks_passed.append("[C] heading_2 '🔗 Related Pages' found at end of Frontend Architecture")
    
        # Check it's near the end
        if related_pages_heading_idx < len(frontend_blocks) - 5:
            errors.append(f"[X] Related Pages should be at end of Frontend Architecture, found at index {related_pages_heading_idx} of {len(frontend_blocks)} blocks")
        else:
            checks_passed.append(f"[C] Related Pages should be at end of Frontend Architecture, found at index {related_pages_heading_idx} of {len(frontend_blocks)} blocks")
    
        # Validate two bookmark blocks after Related Pages heading
        bookmarks_after_heading = [b for b in bookmark_blocks if b["idx"] > related_pages_heading_idx]
        if len(bookmarks_after_heading) < 2:
            errors.append(f"[X] Expected 2 bookmark blocks linking to Component Library and State Management, found {len(bookmarks_after_heading)}")
        else:
            checks_passed.append(f"[C] Found 2 bookmark blocks linking to Component Library and State Management as expected")
    
        # 5. Find Engineering Wiki page
        eng_wiki_pages = _get_pages_by_filter(backend, {"title": "Engineering Wiki"})
        if not eng_wiki_pages:
            errors.append("[X] Engineering Wiki page not found")
        else:
            checks_passed.append("[C] Engineering Wiki page found")
        eng_wiki_page = eng_wiki_pages[0]
    
        eng_wiki_id = eng_wiki_page.get("_id")
        eng_wiki_blocks = _get_blocks_by_filter(backend, {"pageId": eng_wiki_id})
    
        # 6. Validate yellow callout with review dates after first paragraph
        first_paragraph_idx = -1
        review_callout_found = False
    
        for idx, block in enumerate(eng_wiki_blocks):
            block_type = block.get("type", "")
            block_content = block.get("content", "")
            block_properties = block.get("properties", {})
        
            if block_type == "paragraph" and first_paragraph_idx == -1:
                first_paragraph_idx = idx
        
            if block_type == "callout" and first_paragraph_idx != -1 and idx > first_paragraph_idx:
                bg_color = block_properties.get("backgroundColor", "") if isinstance(block_properties, dict) else ""
            
                if ("yellow" in bg_color.lower() and 
                    "last reviewed" in block_content.lower() and 
                    "february 2024" in block_content.lower() and
                    "may 2024" in block_content.lower()):
                    review_callout_found = True
                    break
    
        if first_paragraph_idx == -1:
            errors.append("[X] First paragraph in Engineering Wiki page not found")
        else:
            checks_passed.append("[C] First paragraph in Engineering Wiki page found")
    
        if not review_callout_found:
            errors.append("[X] Yellow callout with review dates 'Last reviewed: February 2024. Next review due: May 2024.' not found after first paragraph in Engineering Wiki")
        else:
            checks_passed.append("[C] Yellow callout with review dates 'Last reviewed: February 2024. Next review due: May 2024.' found after first paragraph in Engineering Wiki")
    
        # ALL requirements met!
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: add-code-quality-standards-to-code-examples-v2
# Description: Add code quality metrics section to Code Examples Repository
# with language distribution and audit date
# =============================================================================
def _validate_agent_add_code_quality_standards_to_code_examples(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate code quality standards addition to Code Examples Repository with:
    - heading_2 '🔍 Code Quality Standards' after image blocks but before first code block
    - Purple callout with 🎯 icon: 'All code examples must follow team style guidelines'
    - heading_3 '📊 Language Distribution' with numbered list showing each language and count
    - Divider block
    - Paragraph with 'Code examples last audited on [TODAY'S DATE]'
    
    NOTE: Italic formatting mentioned but not validated (implementation later)
    
    Returns 1.0 only if ALL requirements are met, otherwise 0.0
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Find the Code Examples Repository page
    try:
        code_examples_pages = _get_pages_by_filter(backend, {"title": "Code Examples Repository"})
        if not code_examples_pages:
            errors.append("[X] Code Examples Repository page not found")
        else:
            checks_passed.append("[C] Code Examples Repository page found")
        code_examples_page = code_examples_pages[0]
    
        code_id = code_examples_page.get("_id")
        code_blocks = _get_blocks_by_filter(backend, {"pageId": code_id})
    
        if len(code_blocks) < 5:
            errors.append(f"[X] Code Examples Repository needs sufficient blocks, found {len(code_blocks)}")
        else:
            checks_passed.append(f"[C] Code Examples Repository needs sufficient blocks, found {len(code_blocks)}")
    
        # 2. Find positions of key elements
        first_image_idx = -1
        last_image_idx = -1
        first_code_idx = -1
        quality_heading_idx = -1
        purple_callout_idx = -1
        lang_dist_heading_idx = -1
        divider_idx = -1
        audit_paragraph_idx = -1
    
        # Track language distribution
        language_counts = {}
        language_list_items = []
    
        for idx, block in enumerate(code_blocks):
            block_type = block.get("type", "")
            block_content = block.get("content", "")
            block_properties = block.get("properties", {})
        
            # Find image blocks
            if block_type == "image":
                if first_image_idx == -1:
                    first_image_idx = idx
                last_image_idx = idx
        
            # Find code blocks and track languages
            if block_type == "code":
                if first_code_idx == -1:
                    first_code_idx = idx
            
                language = block_properties.get("language", "unknown") if isinstance(block_properties, dict) else "unknown"
                language_counts[language] = language_counts.get(language, 0) + 1
        
            # Find Code Quality Standards heading
            if block_type == "heading2" and "code quality standards" in block_content.lower():
                quality_heading_idx = idx
        
            # Find purple callout with target icon
            if block_type == "callout":
                bg_color = block_properties.get("backgroundColor", "") if isinstance(block_properties, dict) else ""
                icon_prop = block_properties.get("icon", "") if isinstance(block_properties, dict) else ""
                icon_value = icon_prop.get("value", "") if isinstance(icon_prop, dict) else str(icon_prop)
            
                if ("purple" in bg_color.lower() and "🎯" in icon_value and 
                    "style guidelines" in block_content.lower()):
                    purple_callout_idx = idx
        
            # Find Language Distribution heading
            if block_type == "heading3" and "language distribution" in block_content.lower():
                lang_dist_heading_idx = idx
        
            # Find numbered list items with language counts
            if block_type == "numberedList" and lang_dist_heading_idx != -1 and idx > lang_dist_heading_idx:
                if ":" in block_content and "example" in block_content.lower():
                    language_list_items.append(block_content)
        
            # Find divider
            if block_type == "divider":
                divider_idx = idx
        
            # Find audit paragraph
            # TODO: Check for italic formatting (implement later)
            if block_type == "paragraph" and "code examples last audited" in block_content.lower():
                audit_paragraph_idx = idx
    
        # 3. Validate Code Quality Standards heading position
        if quality_heading_idx == -1:
            errors.append("[X] heading_2 '🔍 Code Quality Standards' not found")
        else:
            checks_passed.append("[C] heading_2 '🔍 Code Quality Standards' found")
    
        # Should be after images but before first code block
        if last_image_idx != -1 and quality_heading_idx <= last_image_idx:
            errors.append(f"[X] Code Quality Standards should appear after image blocks (last image at {last_image_idx}, heading at {quality_heading_idx})")
        else:
            checks_passed.append(f"[C] Code Quality Standards should appear after image blocks (last image at {last_image_idx}, heading at {quality_heading_idx})")
    
        if first_code_idx != -1 and quality_heading_idx >= first_code_idx:
            errors.append(f"[X] Code Quality Standards should appear before first code block (first code at {first_code_idx}, heading at {quality_heading_idx})")
        else:
            checks_passed.append(f"[C] Code Quality Standards should appear before first code block (first code at {first_code_idx}, heading at {quality_heading_idx})")
    
        # 4. Validate purple callout
        if purple_callout_idx == -1:
            errors.append("[X] Purple callout with 🎯 icon and 'All code examples must follow team style guidelines' not found")
        else:
            checks_passed.append("[C] Purple callout with 🎯 icon and 'All code examples must follow team style guidelines' found")
    
        if purple_callout_idx <= quality_heading_idx:
            errors.append("[X] Purple callout should appear after Code Quality Standards heading")
        else:
            checks_passed.append("[C] Purple callout should appear after Code Quality Standards heading")
    
        # 5. Validate Language Distribution heading
        if lang_dist_heading_idx == -1:
            errors.append("[X] heading_3 '📊 Language Distribution' not found")
        else:
            checks_passed.append("[C] heading_3 '📊 Language Distribution' found")
    
        # 6. Validate language distribution list
        if len(language_list_items) < 1:
            errors.append("[X] Numbered list showing language distribution not found")
        else:
            checks_passed.append("[C] Numbered list showing language distribution found")
    
        # 7. Validate divider
        if divider_idx == -1:
            errors.append("[X] Divider block not found after language distribution")
        else:
            checks_passed.append("[C] Divider block found after language distribution")
    
        # 8. Validate audit paragraph
        if audit_paragraph_idx == -1:
            errors.append("[X] Paragraph with 'Code examples last audited on [date]' not found")
        else:
            checks_passed.append("[C] Paragraph with 'Code examples last audited on [date]' found")
    
        # Verify divider comes before audit paragraph
        if divider_idx >= audit_paragraph_idx:
            errors.append("[X] Divider should appear before audit paragraph")
        else:
            checks_passed.append("[C] Divider should appear before audit paragraph")
    
        # ALL requirements met!
        # TODO: Validate italic formatting when implemented
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: add-development-best-practices-to-guidelines-v2
# Description: Add Development Best Practices section to Project Guidelines
# with 5 practice areas and callout count
# =============================================================================
def _validate_agent_add_development_best_practices_to_guidelines(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate Development Best Practices addition to Project Guidelines with:
    - Content inserted AFTER last callout block
    - heading_1 '💡 Development Best Practices'
    - Orange callout: '🎯 Following these practices ensures code quality and team efficiency'
    - Five heading_2 blocks with specific callouts:
      * '🧪 Testing Standards' with green callout 'Write tests for all new features'
      * '📝 Documentation' with blue callout 'Document all public APIs'
      * '🔍 Code Reviews' with purple callout 'All code must be peer reviewed'
      * '🚀 Performance' with yellow callout 'Profile before optimizing'
      * '🔒 Security' with red callout 'Never commit secrets to version control'
    - Paragraph showing total guideline callout count (original + 6 new)
    
    Returns 1.0 only if ALL requirements are met, otherwise 0.0
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Find the Project Guidelines & Best Practices page
    try:
        guidelines_pages = _get_pages_by_filter(backend, {"title": "Project Guidelines & Best Practices"})
        if not guidelines_pages:
            errors.append("[X] Project Guidelines & Best Practices page not found")
        else:
            checks_passed.append("[C] Project Guidelines & Best Practices page found")
        guidelines_page = guidelines_pages[0]
    
        guidelines_id = guidelines_page.get("_id")
        guidelines_blocks = _get_blocks_by_filter(backend, {"pageId": guidelines_id})
    
        if len(guidelines_blocks) < 10:
            errors.append(f"[X] Project Guidelines needs many blocks for new section, found {len(guidelines_blocks)}")
        else:
            checks_passed.append(f"[C] Project Guidelines needs many blocks for new section, found {len(guidelines_blocks)}")
    
        # 2. Find last callout block and new section elements
        last_callout_idx = -1
        best_practices_heading_idx = -1
        orange_callout_idx = -1
        count_paragraph_idx = -1
    
        # Track the 5 practice headings and callouts
        practice_headings = {
            "testing standards": -1,
            "documentation": -1,
            "code reviews": -1,
            "performance": -1,
            "security": -1
        }
    
        practice_callouts = {
            "testing": None,  # green, "write tests"
            "documentation": None,  # blue, "document all public"
            "reviews": None,  # purple, "peer reviewed"
            "performance": None,  # yellow, "profile before"
            "security": None  # red, "never commit secrets"
        }
    
        total_callouts = 0
    
        for idx, block in enumerate(guidelines_blocks):
            block_type = block.get("type", "")
            block_content = block.get("content", "")
            block_properties = block.get("properties", {})
        
            # Track all callouts
            if block_type == "callout":
                total_callouts += 1
                last_callout_idx = idx
            
                bg_color = block_properties.get("backgroundColor", "") if isinstance(block_properties, dict) else ""
            
                # Check for orange intro callout
                if ("orange" in bg_color.lower() and "quality and team efficiency" in block_content.lower()):
                    orange_callout_idx = idx
            
                # Check for practice-specific callouts
                if "green" in bg_color.lower() and "write tests" in block_content.lower():
                    practice_callouts["testing"] = idx
                elif "blue" in bg_color.lower() and "document all public" in block_content.lower():
                    practice_callouts["documentation"] = idx
                elif "purple" in bg_color.lower() and "peer reviewed" in block_content.lower():
                    practice_callouts["reviews"] = idx
                elif "yellow" in bg_color.lower() and "profile before" in block_content.lower():
                    practice_callouts["performance"] = idx
                elif "red" in bg_color.lower() and "never commit secrets" in block_content.lower():
                    practice_callouts["security"] = idx
        
            # Find main heading
            if block_type == "heading1" and "development best practices" in block_content.lower():
                best_practices_heading_idx = idx
        
            # Find practice headings
            if block_type == "heading2":
                content_lower = block_content.lower()
                if "testing standards" in content_lower:
                    practice_headings["testing standards"] = idx
                elif "documentation" in content_lower and "standards" not in content_lower:
                    practice_headings["documentation"] = idx
                elif "code reviews" in content_lower:
                    practice_headings["code reviews"] = idx
                elif "performance" in content_lower:
                    practice_headings["performance"] = idx
                elif "security" in content_lower:
                    practice_headings["security"] = idx
        
            # Find count paragraph
            if block_type == "paragraph" and "this page now contains" in block_content.lower() and "callouts" in block_content.lower():
                count_paragraph_idx = idx
    
        # 3. Validate main heading exists and is after last original callout
        if best_practices_heading_idx == -1:
            errors.append("[X] heading_1 '💡 Development Best Practices' not found")
        else:
            checks_passed.append("[C] heading_1 '💡 Development Best Practices' found")
    
        # The new section should be near the end (after most original content)
        # We expect it after at least 20+ blocks if page originally had 31 blocks
        if best_practices_heading_idx < 20:
            errors.append(f"[X] Development Best Practices section should be added after existing content, found at index {best_practices_heading_idx}")
        else:
            checks_passed.append(f"[C] Development Best Practices section should be added after existing content, found at index {best_practices_heading_idx}")
    
        # 4. Validate orange intro callout
        if orange_callout_idx == -1:
            errors.append("[X] Orange callout with '🎯 Following these practices ensures code quality and team efficiency' not found")
        else:
            checks_passed.append("[C] Orange callout with '🎯 Following these practices ensures code quality and team efficiency' found")
    
        if orange_callout_idx <= best_practices_heading_idx:
            errors.append("[X] Orange callout should appear after Development Best Practices heading")
        else:
            checks_passed.append("[C] Orange callout should appear after Development Best Practices heading")
    
        # 5. Validate all 5 practice headings
        missing_headings = [name for name, idx in practice_headings.items() if idx == -1]
        if missing_headings:
            errors.append(f"[X] Missing practice heading_2 blocks: {missing_headings}")
        else:
            checks_passed.append(f"[C] has practice heading_2 blocks: {missing_headings}")
    
        # 6. Validate all 5 practice callouts
        missing_callouts = [name for name, idx in practice_callouts.items() if idx is None]
        if missing_callouts:
            errors.append(f"[X] Missing practice callouts with correct colors/text: {missing_callouts}")
        else:
            checks_passed.append(f"[C] has practice callouts with correct colors/text: {missing_callouts}")
    
        # 7. Validate count paragraph
        if count_paragraph_idx == -1:
            errors.append("[X] Paragraph stating 'This page now contains [X] total guideline callouts' not found")
        else:
            checks_passed.append("[C] Paragraph stating 'This page now contains [X] total guideline callouts' found")
    
        # Check if count is accurate (should mention total callouts)
        count_block = guidelines_blocks[count_paragraph_idx]
        count_content = count_block.get("content", "")
    
        if str(total_callouts) not in count_content:
            errors.append(f"[X] Count paragraph should mention {total_callouts} total callouts, but content is: '{count_content}'")
        else:
            checks_passed.append(f"[C] Count paragraph should mention {total_callouts} total callouts, but content is: '{count_content}'")
    
        # ALL requirements met!
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: add-engineering-team-members-to-directory-v2
# Description: Add comprehensive team section to Team Directory after
# Engineering Team heading with 4 team members
# =============================================================================
def _validate_agent_add_engineering_team_members_to_directory(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate engineering team members addition to Team Directory with:
    - Content appears after 'Engineering Team' heading
    - Orange callout with 🚧 icon: 'Section under construction - team data being populated'
    - Four team member entries with heading_3 '👤 [Name] - [Role]':
      * Alice Chen - Senior Engineer (alice@example.com, San Francisco, Frontend)
      * Bob Martinez - Tech Lead (bob@example.com, Austin, Architecture)
      * Carol Williams - Engineer (carol@example.com, Remote, Backend)
      * David Kim - Junior Engineer (david@example.com, Seattle, Full-stack)
    - Each member has 3 bulleted items: Email, Location, Focus with emojis
    - Divider block
    - Paragraph 'Last updated: [today's date]'
    
    Returns 1.0 only if ALL requirements are met, otherwise 0.0
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Find the Team Directory page
    try:
        team_dir_pages = _get_pages_by_filter(backend, {"title": "Team Directory"})
        if not team_dir_pages:
            errors.append("[X] Team Directory page not found")
        else:
            checks_passed.append("[C] Team Directory page found")
        team_dir_page = team_dir_pages[0]
    
        team_dir_id = team_dir_page.get("_id")
        team_blocks = _get_blocks_by_filter(backend, {"pageId": team_dir_id})
    
        if len(team_blocks) < 15:
            errors.append(f"[X] Team Directory needs many blocks for 4 members with details, found {len(team_blocks)}")
        else:
            checks_passed.append(f"[C] Team Directory needs many blocks for 4 members with details, found {len(team_blocks)}")
    
        # 2. Find key elements
        eng_team_heading_idx = -1
        orange_callout_idx = -1
        divider_idx = -1
        last_updated_idx = -1
    
        # Expected team members
        expected_members = {
            "alice chen": {"role": "senior engineer", "email": "alice@example.com", "location": "san francisco", "focus": "frontend"},
            "bob martinez": {"role": "tech lead", "email": "bob@example.com", "location": "austin", "focus": "architecture"},
            "carol williams": {"role": "engineer", "email": "carol@example.com", "location": "remote", "focus": "backend"},
            "david kim": {"role": "junior engineer", "email": "david@example.com", "location": "seattle", "focus": "full-stack"}
        }
    
        found_members = {}
    
        for idx, block in enumerate(team_blocks):
            block_type = block.get("type", "")
            block_content = block.get("content", "")
            block_properties = block.get("properties", {})
        
            # Find Engineering Team heading
            if block_type == "heading2" and "engineering team" in block_content.lower():
                eng_team_heading_idx = idx
        
            # Find orange construction callout
            if block_type == "callout" and eng_team_heading_idx != -1 and idx > eng_team_heading_idx:
                bg_color = block_properties.get("backgroundColor", "") if isinstance(block_properties, dict) else ""
                icon_prop = block_properties.get("icon", "") if isinstance(block_properties, dict) else ""
                icon_value = icon_prop.get("value", "") if isinstance(icon_prop, dict) else str(icon_prop)
            
                if ("orange" in bg_color.lower() and "🚧" in icon_value and 
                    "section under construction" in block_content.lower()):
                    orange_callout_idx = idx
        
            # Find team member headings
            if block_type == "heading3":
                content_lower = block_content.lower()
                for member_name in expected_members.keys():
                    if member_name in content_lower and expected_members[member_name]["role"] in content_lower:
                        found_members[member_name] = {
                            "heading_idx": idx,
                            "has_email": False,
                            "has_location": False,
                            "has_focus": False,
                            "bulleted_count": 0
                        }
        
            # Find bulleted list items for members
            if block_type == "bulletedList":
                content_lower = block_content.lower()
                # Determine which member this belongs to
                for member_name, member_info in found_members.items():
                    if member_info["heading_idx"] != -1 and idx > member_info["heading_idx"]:
                        # Check if next member heading hasn't started yet
                        next_member_heading = min([m["heading_idx"] for m in found_members.values() if m["heading_idx"] > member_info["heading_idx"]], default=999)
                        if idx < next_member_heading or next_member_heading == 999:
                            member_info["bulleted_count"] += 1
                        
                            expected = expected_members[member_name]
                            if "email" in content_lower and expected["email"] in content_lower:
                                member_info["has_email"] = True
                            if "location" in content_lower and expected["location"] in content_lower:
                                member_info["has_location"] = True
                            if "focus" in content_lower and expected["focus"] in content_lower:
                                member_info["has_focus"] = True
        
            # Find divider
            if block_type == "divider":
                divider_idx = idx
        
            # Find last updated paragraph
            if block_type == "paragraph" and "last updated:" in block_content.lower():
                last_updated_idx = idx
    
        # 3. Validate Engineering Team heading
        if eng_team_heading_idx == -1:
            errors.append("[X] Engineering Team heading not found")
        else:
            checks_passed.append("[C] Engineering Team heading found")
    
        # 4. Validate orange construction callout
        if orange_callout_idx == -1:
            errors.append("[X] Orange callout with 🚧 icon and 'Section under construction' not found after Engineering Team heading")
        else:
            checks_passed.append("[C] Orange callout with 🚧 icon and 'Section under construction' found after Engineering Team heading")
    
        if orange_callout_idx <= eng_team_heading_idx:
            errors.append("[X] Orange callout should appear after Engineering Team heading")
        else:
            checks_passed.append("[C] Orange callout should appear after Engineering Team heading")
    
        # 5. Validate all 4 team members found
        if len(found_members) != 4:
            missing = [name for name in expected_members.keys() if name not in found_members]
            errors.append(f"[X] Expected 4 team members, found {len(found_members)}. Missing: {missing}")
        else:
            checks_passed.append(f"[C] Found 4 team members as expected")
    
        # 6. Validate each member has correct details
        for member_name, member_info in found_members.items():
            if member_info["bulleted_count"] != 3:
                errors.append(f"[X] {member_name.title()} should have exactly 3 bulleted items, found {member_info['bulleted_count']}")
            else:
                checks_passed.append(f"[C] {member_name.title()} should have exactly 3 bulleted items, found {member_info['bulleted_count']}")
        
            if not member_info["has_email"]:
                errors.append(f"[X] {member_name.title()} missing email bulleted item with {expected_members[member_name]['email']}")
            else:
                checks_passed.append(f"[C] {member_name.title()} has email bulleted item with {expected_members[member_name]['email']}")
        
            if not member_info["has_location"]:
                errors.append(f"[X] {member_name.title()} missing location bulleted item with {expected_members[member_name]['location']}")
            else:
                checks_passed.append(f"[C] {member_name.title()} has location bulleted item with {expected_members[member_name]['location']}")
        
            if not member_info["has_focus"]:
                errors.append(f"[X] {member_name.title()} missing focus bulleted item with {expected_members[member_name]['focus']}")
            else:
                checks_passed.append(f"[C] {member_name.title()} has focus bulleted item with {expected_members[member_name]['focus']}")
    
        # 7. Validate divider
        if divider_idx == -1:
            errors.append("[X] Divider block not found at end of team section")
        else:
            checks_passed.append("[C] Divider block found at end of team section")
    
        # 8. Validate last updated paragraph
        if last_updated_idx == -1:
            errors.append("[X] Paragraph 'Last updated: [date]' not found at end")
        else:
            checks_passed.append("[C] Paragraph 'Last updated: [date]' found at end")
    
        # Verify divider comes before last updated
        if divider_idx >= last_updated_idx:
            errors.append("[X] Divider should appear before 'Last updated' paragraph")
        else:
            checks_passed.append("[C] Divider should appear before 'Last updated' paragraph")
    
        # ALL requirements met!
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: create-quarterly-goals-tracker-root-v2
# Description: Create new Quarterly Goals Tracker page at root analyzing
# all Goals pages with progress visualization
# =============================================================================
def _validate_agent_create_quarterly_goals_tracker_root(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate Quarterly Goals Tracker creation at root with:
    - New page 'Quarterly Goals Tracker' at root level
    - heading_1 '🎯 Quarterly Goals Tracker'
    - heading_2 '📊 Executive Summary'
    - Blue callout: 'Generated on [date]: Tracking [X] quarters with [Y] total objectives'
    - For each goals page, heading_2 with appropriate emoji based on completion:
      * 🟢 for >50% complete (Q1 Goals: 66% = green)
      * 🔴 for <25% complete (Q2 Goals: 0% = red)
    - Progress bar visualization using ✅ and ⬜ (Q1: ✅✅⬜, Q2: ⬜⬜)
    - heading_2 '🚀 Next Steps' with numbered list of 3 unchecked tasks
    
    Returns 1.0 only if ALL requirements are met, otherwise 0.0
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Find the Quarterly Goals Tracker page (should be at root)
    try:
        tracker_pages = _get_pages_by_filter(backend, {"title": "Quarterly Goals Tracker"})
        if not tracker_pages:
            errors.append("[X] Quarterly Goals Tracker page not found")
        else:
            checks_passed.append("[C] Quarterly Goals Tracker page found")
        tracker_page = tracker_pages[0]
    
        # Check if at root level (parentId should be null or empty)
        parent_id = tracker_page.get("parentId")
        if parent_id:
            errors.append(f"[X] Quarterly Goals Tracker should be at root level, but has parentId: {parent_id}")
        else:
            checks_passed.append(f"[C] Quarterly Goals Tracker should be at root level, but has parentId: {parent_id}")
    
        tracker_id = tracker_page.get("_id")
        tracker_blocks = _get_blocks_by_filter(backend, {"pageId": tracker_id})
    
        if len(tracker_blocks) < 8:
            errors.append(f"[X] Quarterly Goals Tracker needs sufficient blocks, found {len(tracker_blocks)}")
        else:
            checks_passed.append(f"[C] Quarterly Goals Tracker needs sufficient blocks, found {len(tracker_blocks)}")
    
        # 2. Find key structural elements
        main_heading_idx = -1
        exec_summary_heading_idx = -1
        blue_callout_idx = -1
        q1_heading_idx = -1
        q2_heading_idx = -1
        q1_progress_found = False
        q2_progress_found = False
        next_steps_heading_idx = -1
        next_steps_tasks = []
    
        for idx, block in enumerate(tracker_blocks):
            block_type = block.get("type", "")
            block_content = block.get("content", "")
            block_properties = block.get("properties", {})
        
            # Find main heading
            if block_type == "heading1" and "quarterly goals tracker" in block_content.lower():
                main_heading_idx = idx
        
            # Find Executive Summary heading
            if block_type == "heading2" and "executive summary" in block_content.lower():
                exec_summary_heading_idx = idx
        
            # Find blue callout with generation info
            if block_type == "callout":
                bg_color = block_properties.get("backgroundColor", "") if isinstance(block_properties, dict) else ""
            
                if ("blue" in bg_color.lower() and "generated on" in block_content.lower() and 
                    "tracking" in block_content.lower() and "quarters" in block_content.lower()):
                    blue_callout_idx = idx
        
            # Find Q1 Goals heading (should have green emoji 🟢)
            if block_type == "heading2" and "q1 goals" in block_content.lower():
                if "🟢" in block_content:
                    q1_heading_idx = idx
        
            # Find Q2 Goals heading (should have red emoji 🔴)
            if block_type == "heading2" and "q2 goals" in block_content.lower():
                if "🔴" in block_content:
                    q2_heading_idx = idx
        
            # Find progress bar paragraphs
            if block_type == "paragraph":
                # Q1 should show ✅✅⬜ (2 done, 1 pending)
                if "✅✅⬜" in block_content or ("✅" in block_content and block_content.count("✅") == 2 and "⬜" in block_content):
                    q1_progress_found = True
            
                # Q2 should show ⬜⬜ (0 done, 2 pending)
                if "⬜⬜" in block_content or (block_content.count("⬜") >= 2 and "✅" not in block_content):
                    q2_progress_found = True
        
            # Find Next Steps heading
            if block_type == "heading2" and "next steps" in block_content.lower():
                next_steps_heading_idx = idx
        
            # Find numbered list items for next steps
            if block_type == "numberedList" and next_steps_heading_idx != -1 and idx > next_steps_heading_idx:
                next_steps_tasks.append(idx)
    
        # 3. Validate main heading
        if main_heading_idx == -1:
            errors.append("[X] Main heading_1 '🎯 Quarterly Goals Tracker' not found")
        else:
            checks_passed.append("[C] Main heading_1 '🎯 Quarterly Goals Tracker' found")
    
        # 4. Validate Executive Summary heading
        if exec_summary_heading_idx == -1:
            errors.append("[X] heading_2 '📊 Executive Summary' not found")
        else:
            checks_passed.append("[C] heading_2 '📊 Executive Summary' found")
    
        # 5. Validate blue callout
        if blue_callout_idx == -1:
            errors.append("[X] Blue callout with 'Generated on [date]: Tracking [X] quarters with [Y] total objectives' not found")
        else:
            checks_passed.append("[C] Blue callout with 'Generated on [date]: Tracking [X] quarters with [Y] total objectives' found")
    
        # 6. Validate Q1 Goals heading with green emoji
        if q1_heading_idx == -1:
            errors.append("[X] heading_2 for Q1 Goals with 🟢 emoji (>50% complete) not found")
        else:
            checks_passed.append("[C] heading_2 for Q1 Goals with 🟢 emoji (>50% complete) found")
    
        # 7. Validate Q2 Goals heading with red emoji
        if q2_heading_idx == -1:
            errors.append("[X] heading_2 for Q2 Goals with 🔴 emoji (<25% complete) not found")
        else:
            checks_passed.append("[C] heading_2 for Q2 Goals with 🔴 emoji (<25% complete) found")
    
        # 8. Validate Q1 progress bar
        if not q1_progress_found:
            errors.append("[X] Q1 progress bar visualization '✅✅⬜' (2 of 3 complete) not found")
        else:
            checks_passed.append("[C] Q1 progress bar visualization '✅✅⬜' (2 of 3 complete) found")
    
        # 9. Validate Q2 progress bar
        if not q2_progress_found:
            errors.append("[X] Q2 progress bar visualization '⬜⬜' (0 of 2 complete) not found")
        else:
            checks_passed.append("[C] Q2 progress bar visualization '⬜⬜' (0 of 2 complete) found")
    
        # 10. Validate Next Steps heading
        if next_steps_heading_idx == -1:
            errors.append("[X] heading_2 '🚀 Next Steps' not found")
        else:
            checks_passed.append("[C] heading_2 '🚀 Next Steps' found")
    
        # 11. Validate Next Steps has 3 tasks
        if len(next_steps_tasks) != 3:
            errors.append(f"[X] Next Steps should have numbered list with exactly 3 unchecked tasks, found {len(next_steps_tasks)}")
        else:
            checks_passed.append(f"[C] Next Steps should have numbered list with exactly 3 unchecked tasks, found {len(next_steps_tasks)}")
    
        # ALL requirements met!
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: add-team-statistics-to-directory-v2
# Description: Add Team Statistics section to Team Directory after Team Photo
# with calculated member counts and percentages
# =============================================================================
def _validate_agent_add_team_statistics_to_directory(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate Team Statistics addition to Team Directory with:
    - heading_2 '📈 Team Statistics' after Team Photo image block
    - Gray callout with 👥 icon: 'Last updated: [TODAY'S DATE]'
    - Bulleted list with:
      * 'Total team size: [X] members'
      * 'Engineering: [Y] members ([Z]% of total)'
      * 'Design: [A] members ([B]% of total)'
    - All counts and percentages calculated from actual team members
    
    Returns 1.0 only if ALL requirements are met, otherwise 0.0
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Find the Team Directory page
    try:
        team_dir_pages = _get_pages_by_filter(backend, {"title": "Team Directory"})
        if not team_dir_pages:
            errors.append("[X] Team Directory page not found")
        else:
            checks_passed.append("[C] Team Directory page found")
        team_dir_page = team_dir_pages[0]
    
        team_dir_id = team_dir_page.get("_id")
        team_blocks = _get_blocks_by_filter(backend, {"pageId": team_dir_id})
    
        if len(team_blocks) < 5:
            errors.append(f"[X] Team Directory needs sufficient blocks, found {len(team_blocks)}")
        else:
            checks_passed.append(f"[C] Team Directory needs sufficient blocks, found {len(team_blocks)}")
    
        # 2. Find key elements
        team_photo_idx = -1
        statistics_heading_idx = -1
        gray_callout_idx = -1
    
        total_members_bullet = None
        engineering_bullet = None
        design_bullet = None
    
        for idx, block in enumerate(team_blocks):
            block_type = block.get("type", "")
            block_content = block.get("content", "")
            block_properties = block.get("properties", {})
        
            # Find Team Photo image
            if block_type == "image":
                # Check if this is the team photo (could have "team" in content/alt)
                team_photo_idx = idx  # Assume last/only image is team photo
        
            # Find Team Statistics heading
            if block_type == "heading2" and "team statistics" in block_content.lower():
                statistics_heading_idx = idx
        
            # Find gray callout with people emoji
            if block_type == "callout":
                bg_color = block_properties.get("backgroundColor", "") if isinstance(block_properties, dict) else ""
                icon_prop = block_properties.get("icon", "") if isinstance(block_properties, dict) else ""
                icon_value = icon_prop.get("value", "") if isinstance(icon_prop, dict) else str(icon_prop)
            
                if ("gray" in bg_color.lower() and "👥" in icon_value and 
                    "last updated:" in block_content.lower()):
                    gray_callout_idx = idx
        
            # Find bulleted list items with team stats
            if block_type == "bulletedList":
                content_lower = block_content.lower()
            
                if "total team size:" in content_lower and "members" in content_lower:
                    total_members_bullet = block_content
                elif "engineering:" in content_lower and "%" in block_content:
                    engineering_bullet = block_content
                elif "design:" in content_lower and "%" in block_content:
                    design_bullet = block_content
    
        # 3. Validate Team Photo exists
        if team_photo_idx == -1:
            errors.append("[X] Team Photo image block not found")
        else:
            checks_passed.append("[C] Team Photo image block found")
    
        # 4. Validate Team Statistics heading appears after Team Photo
        if statistics_heading_idx == -1:
            errors.append("[X] heading_2 '📈 Team Statistics' not found")
        else:
            checks_passed.append("[C] heading_2 '📈 Team Statistics' found")
    
        if statistics_heading_idx <= team_photo_idx:
            errors.append(f"[X] Team Statistics heading should appear after Team Photo (photo at {team_photo_idx}, heading at {statistics_heading_idx})")
        else:
            checks_passed.append(f"[C] Team Statistics heading should appear after Team Photo (photo at {team_photo_idx}, heading at {statistics_heading_idx})")
    
        # 5. Validate gray callout
        if gray_callout_idx == -1:
            errors.append("[X] Gray callout with 👥 icon and 'Last updated: [date]' not found")
        else:
            checks_passed.append("[C] Gray callout with 👥 icon and 'Last updated: [date]' found")
    
        if gray_callout_idx <= statistics_heading_idx:
            errors.append("[X] Gray callout should appear after Team Statistics heading")
        else:
            checks_passed.append("[C] Gray callout should appear after Team Statistics heading")
    
        # 6. Validate bulleted list items
        if not total_members_bullet:
            errors.append("[X] Bulleted item 'Total team size: [X] members' not found")
        else:
            checks_passed.append("[C] Bulleted item 'Total team size: [X] members' found")
    
        if not engineering_bullet:
            errors.append("[X] Bulleted item 'Engineering: [Y] members ([Z]% of total)' not found")
        else:
            checks_passed.append("[C] Bulleted item 'Engineering: [Y] members ([Z]% of total)' found")
    
        if not design_bullet:
            errors.append("[X] Bulleted item 'Design: [A] members ([B]% of total)' not found")
        else:
            checks_passed.append("[C] Bulleted item 'Design: [A] members ([B]% of total)' found")
    
        # 7. Validate that counts make sense (should have numbers and percentages)
        # Extract numbers from bullets to check they're reasonable
        import re
    
        # Check total members has a number
        if not re.search(r'\d+', total_members_bullet):
            errors.append(f"[X] Total team size should contain a number, found: '{total_members_bullet}'")
        else:
            checks_passed.append(f"[C] Total team size should contain a number, found: '{total_members_bullet}'")
    
        # Check engineering has count and percentage (accept both "member" and "members")
        if not (re.search(r'\d+\s+members?', engineering_bullet) and re.search(r'\d+%', engineering_bullet)):
            errors.append(f"[X] Engineering should contain member count and percentage, found: '{engineering_bullet}'")
        else:
            checks_passed.append(f"[C] Engineering should contain member count and percentage, found: '{engineering_bullet}'")

        # Check design has count and percentage (accept both "member" and "members")
        if not (re.search(r'\d+\s+members?', design_bullet) and re.search(r'\d+%', design_bullet)):
            errors.append(f"[X] Design should contain member count and percentage, found: '{design_bullet}'")
        else:
            checks_passed.append(f"[C] Design should contain member count and percentage, found: '{design_bullet}'")
    
        # ALL requirements met!
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: add-callout-usage-statistics-to-guidelines-v2
# Description: Add Callout Usage Statistics section to Project Guidelines
# after red production deployments callout
# =============================================================================
def _validate_agent_add_callout_usage_statistics_to_guidelines(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate Callout Usage Statistics addition to Project Guidelines with:
    - Section inserted immediately AFTER red 'Critical: Production deployments' callout
    - heading_2 '📈 Callout Usage Statistics'
    - Paragraph: 'This page contains [TOTAL] callout blocks distributed as follows:'
    - Numbered list showing each background color and count:
      * '1. Yellow background: [X] callouts'
      * '2. Orange background: [Y] callouts'
      * '3. Red background: [Z] callouts'
    - Quote block: 'Callouts are most effective when used sparingly to highlight critical information.'
    
    Returns 1.0 only if ALL requirements are met, otherwise 0.0
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Find the Project Guidelines & Best Practices page
    try:
        guidelines_pages = _get_pages_by_filter(backend, {"title": "Project Guidelines & Best Practices"})
        if not guidelines_pages:
            errors.append("[X] Project Guidelines & Best Practices page not found")
        else:
            checks_passed.append("[C] Project Guidelines & Best Practices page found")
        guidelines_page = guidelines_pages[0]
    
        guidelines_id = guidelines_page.get("_id")
        guidelines_blocks = _get_blocks_by_filter(backend, {"pageId": guidelines_id})
    
        if len(guidelines_blocks) < 5:
            errors.append(f"[X] Project Guidelines needs sufficient blocks, found {len(guidelines_blocks)}")
        else:
            checks_passed.append(f"[C] Project Guidelines needs sufficient blocks, found {len(guidelines_blocks)}")
    
        # 2. Find key elements
        red_production_callout_idx = -1
        statistics_heading_idx = -1
        statistics_paragraph_idx = -1
        quote_idx = -1
    
        color_counts = {}
        color_list_items = []
        total_callouts = 0
    
        for idx, block in enumerate(guidelines_blocks):
            block_type = block.get("type", "")
            block_content = block.get("content", "")
            block_properties = block.get("properties", {})
        
            # Count all callouts and track colors
            if block_type == "callout":
                total_callouts += 1
                bg_color = block_properties.get("backgroundColor", "") if isinstance(block_properties, dict) else ""
            
                if bg_color:
                    color_key = bg_color.lower().replace("_background", "").replace("background", "").strip()
                    color_counts[color_key] = color_counts.get(color_key, 0) + 1
            
                # Find FIRST red production deployments callout
                if (red_production_callout_idx == -1 and
                    "red" in bg_color.lower() and 
                    ("production deployment" in block_content.lower() or "critical:" in block_content.lower())):
                    red_production_callout_idx = idx
        
            # Find Callout Usage Statistics heading
            if block_type == "heading2" and "callout usage statistics" in block_content.lower():
                statistics_heading_idx = idx
        
            # Find statistics paragraph
            if block_type == "paragraph" and "this page contains" in block_content.lower() and "callout blocks distributed" in block_content.lower():
                statistics_paragraph_idx = idx
        
            # Find numbered list items with color counts
            if block_type == "numberedList" and statistics_heading_idx != -1 and idx > statistics_heading_idx:
                if "background:" in block_content.lower() and "callout" in block_content.lower():
                    color_list_items.append(block_content)
        
            # Find quote about callouts
            if block_type == "quote" and "callouts are most effective" in block_content.lower() and "sparingly" in block_content.lower():
                quote_idx = idx
    
        # 3. Validate red production callout was found
        if red_production_callout_idx == -1:
            errors.append("[X] Red callout about 'Critical: Production deployments' not found")
        else:
            checks_passed.append("[C] Red callout about 'Critical: Production deployments' found")
    
        # 4. Validate statistics heading appears after red callout
        if statistics_heading_idx == -1:
            errors.append("[X] heading_2 '📈 Callout Usage Statistics' not found")
        else:
            checks_passed.append("[C] heading_2 '📈 Callout Usage Statistics' found")
    
        if statistics_heading_idx <= red_production_callout_idx:
            errors.append(f"[X] Callout Usage Statistics heading should appear after red production callout (red at {red_production_callout_idx}, heading at {statistics_heading_idx})")
        else:
            checks_passed.append(f"[C] Callout Usage Statistics heading should appear after red production callout (red at {red_production_callout_idx}, heading at {statistics_heading_idx})")
    
        # Check it's immediately after (within a few blocks)
        if statistics_heading_idx > red_production_callout_idx + 3:
            errors.append(f"[X] Callout Usage Statistics should appear immediately after red callout, found {statistics_heading_idx - red_production_callout_idx} blocks apart")
        else:
            checks_passed.append(f"[C] Callout Usage Statistics should appear immediately after red callout, found {statistics_heading_idx - red_production_callout_idx} blocks apart")
    
        # 5. Validate statistics paragraph
        if statistics_paragraph_idx == -1:
            errors.append("[X] Paragraph 'This page contains [TOTAL] callout blocks distributed as follows:' not found")
        else:
            checks_passed.append("[C] Paragraph 'This page contains [TOTAL] callout blocks distributed as follows:' found")
    
        # Check paragraph mentions total count
        paragraph_block = guidelines_blocks[statistics_paragraph_idx]
        paragraph_content = paragraph_block.get("content", "")
    
        if str(total_callouts) not in paragraph_content:
            errors.append(f"[X] Statistics paragraph should mention {total_callouts} total callouts, but content is: '{paragraph_content}'")
        else:
            checks_passed.append(f"[C] Statistics paragraph should mention {total_callouts} total callouts, but content is: '{paragraph_content}'")
    
        # 6. Validate numbered list with color counts
        if len(color_list_items) < 3:
            errors.append(f"[X] Expected numbered list with at least 3 color/count entries, found {len(color_list_items)}")
        else:
            checks_passed.append(f"[C] Expected numbered list with at least 3 color/count entries, found {len(color_list_items)}")
    
        # Check that list mentions Yellow, Orange, Red
        all_colors_text = " ".join(color_list_items).lower()
        required_colors = ["yellow", "orange", "red"]
        missing_colors = [c for c in required_colors if c not in all_colors_text]
    
        if missing_colors:
            errors.append(f"[X] Numbered list should mention {required_colors} backgrounds, missing: {missing_colors}")
        else:
            checks_passed.append(f"[C] Numbered list should mention {required_colors} backgrounds, has: {missing_colors}")
    
        # 7. Validate quote
        if quote_idx == -1:
            errors.append("[X] Quote block 'Callouts are most effective when used sparingly to highlight critical information.' not found")
        else:
            checks_passed.append("[C] Quote block 'Callouts are most effective when used sparingly to highlight critical information.' found")
    
        # Quote should come after the numbered list
        if quote_idx <= statistics_heading_idx:
            errors.append("[X] Quote should appear after the statistics section")
        else:
            checks_passed.append("[C] Quote should appear after the statistics section")
    
        # ALL requirements met!
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: add-technical-debt-items-to-sprint-planning-v2
# Description: Add Technical Debt Items section to Sprint Planning between
# Action Items heading and existing todos
# =============================================================================
def _validate_agent_add_technical_debt_items_to_sprint_planning(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate Technical Debt Items addition to Sprint Planning with:
    - New section inserted AFTER 'Action Items' heading but BEFORE existing to-do blocks
    - heading_2 '🔧 Technical Debt Items'
    - Paragraph: 'Critical refactoring tasks identified during the sprint:'
    - Three unchecked todo blocks:
      * '⚡ Optimize database queries in user service'
      * '🔄 Refactor authentication middleware'
      * '📦 Update deprecated npm packages'
    - Divider block after last todo
    
    Returns 1.0 only if ALL requirements are met, otherwise 0.0
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Find the Sprint Planning - Jan 15 page
    try:
        sprint_pages = _get_pages_by_filter(backend, {"title": "Sprint Planning - Jan 15"})
        if not sprint_pages:
            errors.append("[X] Sprint Planning - Jan 15 page not found")
        else:
            checks_passed.append("[C] Sprint Planning - Jan 15 page found")
        sprint_page = sprint_pages[0]
    
        sprint_id = sprint_page.get("_id")
        sprint_blocks = _get_blocks_by_filter(backend, {"pageId": sprint_id})
    
        if len(sprint_blocks) < 6:
            errors.append(f"[X] Sprint Planning needs sufficient blocks, found {len(sprint_blocks)}")
        else:
            checks_passed.append(f"[C] Sprint Planning needs sufficient blocks, found {len(sprint_blocks)}")
    
        # 2. Find key elements
        action_items_heading_idx = -1
        tech_debt_heading_idx = -1
        tech_debt_paragraph_idx = -1
        divider_idx = -1
    
        first_existing_todo_idx = -1
    
        expected_todos = [
            "optimize database queries in user service",
            "refactor authentication middleware",
            "update deprecated npm packages"
        ]
        found_tech_debt_todos = []
    
        for idx, block in enumerate(sprint_blocks):
            block_type = block.get("type", "")
            block_content = block.get("content", "")
            block_properties = block.get("properties", {})
        
            # Find Action Items heading
            if block_type == "heading2" and "action items" in block_content.lower():
                action_items_heading_idx = idx
        
            # Find Technical Debt Items heading
            if block_type == "heading2" and "technical debt items" in block_content.lower():
                tech_debt_heading_idx = idx
        
            # Find technical debt paragraph
            if block_type == "paragraph" and "critical refactoring tasks" in block_content.lower():
                tech_debt_paragraph_idx = idx
        
            # Find todos
            if block_type == "todo":
                content_lower = block_content.lower()
            
                # Check if this is one of our technical debt todos
                is_tech_debt = False
                for expected_todo in expected_todos:
                    if expected_todo in content_lower:
                        is_checked = block_properties.get("checked", False) if isinstance(block_properties, dict) else False
                        found_tech_debt_todos.append({
                            "idx": idx,
                            "content": block_content,
                            "checked": is_checked,
                            "expected": expected_todo
                        })
                        is_tech_debt = True
                        break
            
                # Track first existing (non-tech-debt) todo
                if not is_tech_debt and action_items_heading_idx != -1 and idx > action_items_heading_idx:
                    if first_existing_todo_idx == -1:
                        first_existing_todo_idx = idx
        
            # Find divider
            if block_type == "divider":
                # Check if this divider is after our tech debt todos
                if tech_debt_heading_idx != -1 and idx > tech_debt_heading_idx:
                    if divider_idx == -1:  # Take first divider after tech debt heading
                        divider_idx = idx
    
        # 3. Validate Action Items heading
        if action_items_heading_idx == -1:
            errors.append("[X] Action Items heading not found")
        else:
            checks_passed.append("[C] Action Items heading found")
    
        # 4. Validate Technical Debt Items heading appears after Action Items
        if tech_debt_heading_idx == -1:
            errors.append("[X] heading_2 '🔧 Technical Debt Items' not found")
        else:
            checks_passed.append("[C] heading_2 '🔧 Technical Debt Items' found")
    
        if tech_debt_heading_idx <= action_items_heading_idx:
            errors.append("[X] Technical Debt Items heading should appear after Action Items heading")
        else:
            checks_passed.append("[C] Technical Debt Items heading should appear after Action Items heading")
    
        # 5. Validate heading appears before existing todos (if any)
        if first_existing_todo_idx != -1:
            if tech_debt_heading_idx >= first_existing_todo_idx:
                errors.append(f"[X] Technical Debt Items heading should appear BEFORE existing todos (heading at {tech_debt_heading_idx}, first todo at {first_existing_todo_idx})")
            else:
                checks_passed.append(f"[C] Technical Debt Items heading should appear BEFORE existing todos (heading at {tech_debt_heading_idx}, first todo at {first_existing_todo_idx})")
    
        # 6. Validate technical debt paragraph
        if tech_debt_paragraph_idx == -1:
            errors.append("[X] Paragraph 'Critical refactoring tasks identified during the sprint:' not found")
        else:
            checks_passed.append("[C] Paragraph 'Critical refactoring tasks identified during the sprint:' found")
    
        if tech_debt_paragraph_idx <= tech_debt_heading_idx:
            errors.append("[X] Technical debt paragraph should appear after Technical Debt Items heading")
        else:
            checks_passed.append("[C] Technical debt paragraph should appear after Technical Debt Items heading")
    
        # 7. Validate three technical debt todos
        if len(found_tech_debt_todos) != 3:
            missing = [exp for exp in expected_todos if not any(ft["expected"] == exp for ft in found_tech_debt_todos)]
            errors.append(f"[X] Expected 3 specific technical debt todos, found {len(found_tech_debt_todos)}. Missing: {missing}")
        else:
            checks_passed.append(f"[C] Found 3 specific technical debt todos as expected")
    
        # 8. Check all todos are unchecked
        checked_todos = [ft for ft in found_tech_debt_todos if ft["checked"]]
        if checked_todos:
            errors.append(f"[X] All technical debt todos should be unchecked, found {len(checked_todos)} checked")
        else:
            checks_passed.append(f"[C] All technical debt todos should be unchecked, found {len(checked_todos)} checked")
    
        # 9. Validate divider after last todo
        if divider_idx == -1:
            errors.append("[X] Divider block not found after technical debt todos")
        else:
            checks_passed.append("[C] Divider block found after technical debt todos")
    
        last_tech_debt_todo_idx = max(ft["idx"] for ft in found_tech_debt_todos)
        if divider_idx <= last_tech_debt_todo_idx:
            errors.append(f"[X] Divider should appear after last technical debt todo (last todo at {last_tech_debt_todo_idx}, divider at {divider_idx})")
        else:
            checks_passed.append(f"[C] Divider should appear after last technical debt todo (last todo at {last_tech_debt_todo_idx}, divider at {divider_idx})")
    
        # ALL requirements met!
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: create-meeting-notes-archive-summary-v2
# Description: Create comprehensive Meeting Notes Archive Summary analyzing all
# child meeting pages with toggle index, statistics callout, and detailed breakdowns
# =============================================================================
def _validate_agent_create_meeting_notes_archive_summary(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate creation of Meeting Notes Archive Summary page with:
    - Page exists as child of 'Meeting Notes'
    - heading_1 '📚 Meeting Notes Archive Summary'
    - Toggle block '📅 Meeting Index (Click to expand)' with bulleted list of meeting titles/icons
    - heading_2 '📊 Meeting Statistics'
    - Callout with gray_background containing table-like structure:
      * 'Total Meetings Documented: [X]'
      * 'Meetings with Action Items: [Y]'
      * 'Average Blocks per Meeting: [Z]'
    - For each meeting page:
      * heading_3 '[Icon] [Meeting Title]'
      * Quote block 'Meeting date: [extracted date]'
      * Paragraph 'Content blocks: [count] | Todo items: [todo count]'
    
    Returns 1.0 only if ALL requirements are met, otherwise 0.0
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Find the 'Meeting Notes' page
    try:
        meeting_notes_page = _find_page_by_title(final_state_backend, "Meeting Notes")
        if not meeting_notes_page:
            errors.append("[X] Meeting Notes page not found")
        else:
            checks_passed.append("[C] Meeting Notes page found")
    
        meeting_notes_id = meeting_notes_page.get("_id")
    
        # 2. Find the 'Meeting Notes Archive Summary' page
        archive_summary_page = _find_page_by_title(final_state_backend, "Meeting Notes Archive Summary")
        if not archive_summary_page:
            errors.append("[X] Meeting Notes Archive Summary page not found")
        else:
            checks_passed.append("[C] Meeting Notes Archive Summary page found")
    
        archive_summary_id = archive_summary_page.get("_id")
    
        # 3. Verify it's a child of Meeting Notes
        if not _check_page_is_child_of(meeting_notes_page, archive_summary_page):
            errors.append("[X] Meeting Notes Archive Summary is not a child of Meeting Notes")
        else:
            checks_passed.append("[C] Meeting Notes Archive Summary is a child of Meeting Notes")
    
        # 4. Get all child pages of Meeting Notes (excluding the summary page itself)
        all_meeting_children = _get_child_pages(final_state_backend, meeting_notes_id)
        meeting_children = [p for p in all_meeting_children if p.get("_id") != archive_summary_id]
    
        if len(meeting_children) == 0:
            errors.append("[X] No meeting child pages found under Meeting Notes to analyze")
        else:
            checks_passed.append("[C] meeting child pages found under Meeting Notes to analyze")
    
        # 5. Get blocks for the archive summary page
        summary_blocks = _get_blocks_for_page(final_state_backend, archive_summary_id)
    
        if len(summary_blocks) < 8:
            errors.append(f"[X] Archive Summary needs many blocks (heading, toggle, statistics, etc.), found {len(summary_blocks)}")
        else:
            checks_passed.append(f"[C] Archive Summary needs many blocks (heading, toggle, statistics, etc.), found {len(summary_blocks)}")
    
        # 6. Find key elements in summary page
        main_heading_idx = -1
        toggle_block_idx = -1
        statistics_heading_idx = -1
        statistics_callout_idx = -1
    
        # Track meeting index bullets within toggle
        meeting_index_bullets = []
    
        # Track meeting detail sections (heading_3, quote, paragraph)
        meeting_sections = []
    
        for idx, block in enumerate(summary_blocks):
            block_type = block.get("type", "")
            block_content = block.get("content", "")
            block_properties = block.get("properties", {})
        
            # Find main heading
            if block_type == "heading1" and "📚" in block_content and "meeting notes archive summary" in block_content.lower():
                main_heading_idx = idx
        
            # Find toggle block
            if block_type == "toggle" and "📅" in block_content and "meeting index" in block_content.lower():
                toggle_block_idx = idx
        
            # Find statistics heading
            if block_type == "heading2" and "📊" in block_content and "meeting statistics" in block_content.lower():
                statistics_heading_idx = idx
        
            # Find gray statistics callout
            if block_type == "callout" and statistics_heading_idx != -1 and idx > statistics_heading_idx:
                bg_color = block_properties.get("backgroundColor", "") if isinstance(block_properties, dict) else ""
                if "gray" in bg_color.lower() or "grey" in bg_color.lower():
                    content_lower = block_content.lower()
                    if "total meetings documented:" in content_lower and "meetings with action items:" in content_lower:
                        statistics_callout_idx = idx
        
            # Find bulleted list items (these should be within or near toggle)
            if block_type == "bulletedList" and toggle_block_idx != -1:
                # Should be shortly after toggle block
                if idx > toggle_block_idx and (statistics_heading_idx == -1 or idx < statistics_heading_idx):
                    meeting_index_bullets.append({
                        "idx": idx,
                        "content": block_content
                    })
        
            # Find meeting detail sections (heading_3 with icon + meeting title)
            if block_type == "heading3" and statistics_callout_idx != -1 and idx > statistics_callout_idx:
                # This should be a meeting title with icon
                meeting_sections.append({
                    "heading_idx": idx,
                    "heading_content": block_content,
                    "quote_idx": -1,
                    "paragraph_idx": -1
                })
        
            # Find quote blocks (should follow heading_3)
            if block_type == "quote" and len(meeting_sections) > 0:
                # Associate with last meeting section if it doesn't have a quote yet
                if meeting_sections[-1]["quote_idx"] == -1 and idx > meeting_sections[-1]["heading_idx"]:
                    content_lower = block_content.lower()
                    if "meeting date:" in content_lower or "date:" in content_lower:
                        meeting_sections[-1]["quote_idx"] = idx
        
            # Find paragraph blocks with stats (should follow quote)
            if block_type == "paragraph" and len(meeting_sections) > 0:
                # Associate with last meeting section if it has a quote but no paragraph yet
                if (meeting_sections[-1]["quote_idx"] != -1 and 
                    meeting_sections[-1]["paragraph_idx"] == -1 and 
                    idx > meeting_sections[-1]["quote_idx"]):
                    content_lower = block_content.lower()
                    if "content blocks:" in content_lower and "todo items:" in content_lower:
                        meeting_sections[-1]["paragraph_idx"] = idx
    
        # 7. Validate main heading exists
        if main_heading_idx == -1:
            errors.append("[X] heading_1 '📚 Meeting Notes Archive Summary' not found")
        else:
            checks_passed.append("[C] heading_1 '📚 Meeting Notes Archive Summary' found")
    
        # 8. Validate toggle block exists
        if toggle_block_idx == -1:
            errors.append("[X] Toggle block '📅 Meeting Index (Click to expand)' not found")
        else:
            checks_passed.append("[C] Toggle block '📅 Meeting Index (Click to expand)' found")
    
        # 9. Validate toggle is after main heading
        if toggle_block_idx <= main_heading_idx:
            errors.append(f"[X] Toggle block should appear after main heading (heading at {main_heading_idx}, toggle at {toggle_block_idx})")
        else:
            checks_passed.append(f"[C] Toggle block should appear after main heading (heading at {main_heading_idx}, toggle at {toggle_block_idx})")
    
        # 10. Validate meeting index bullets exist
        if len(meeting_index_bullets) < len(meeting_children):
            errors.append(f"[X] Expected at least {len(meeting_children)} bulleted items in Meeting Index (one per meeting child), found {len(meeting_index_bullets)}")
        else:
            checks_passed.append(f"[C] Expected at least {len(meeting_children)} bulleted items in Meeting Index (one per meeting child), found {len(meeting_index_bullets)}")
    
        # 11. Validate statistics heading exists
        if statistics_heading_idx == -1:
            errors.append("[X] heading_2 '📊 Meeting Statistics' not found")
        else:
            checks_passed.append("[C] heading_2 '📊 Meeting Statistics' found")
    
        # 12. Validate statistics heading is after toggle
        if statistics_heading_idx <= toggle_block_idx:
            errors.append(f"[X] Statistics heading should appear after toggle block (toggle at {toggle_block_idx}, heading at {statistics_heading_idx})")
        else:
            checks_passed.append(f"[C] Statistics heading should appear after toggle block (toggle at {toggle_block_idx}, heading at {statistics_heading_idx})")
    
        # 13. Validate gray statistics callout exists
        if statistics_callout_idx == -1:
            errors.append("[X] Gray callout with meeting statistics not found (should contain 'Total Meetings Documented', 'Meetings with Action Items', 'Average Blocks per Meeting')")
        else:
            checks_passed.append("[C] Gray callout with meeting statistics found (should contain 'Total Meetings Documented', 'Meetings with Action Items', 'Average Blocks per Meeting')")
    
        # 14. Analyze actual meeting pages to validate statistics accuracy
        total_meetings = len(meeting_children)
        meetings_with_action_items = 0
        total_blocks_count = 0
    
        for meeting_child in meeting_children:
            meeting_blocks = _get_blocks_for_page(final_state_backend, meeting_child.get("_id"))
            total_blocks_count += len(meeting_blocks)
        
            # Check if has todo items
            has_todos = any(b.get("type") == "todo" for b in meeting_blocks)
            if has_todos:
                meetings_with_action_items += 1
    
        avg_blocks = round(total_blocks_count / total_meetings, 1) if total_meetings > 0 else 0
    
        # 15. Validate statistics callout mentions correct counts
        callout_block = summary_blocks[statistics_callout_idx]
        callout_content = callout_block.get("content", "")
        callout_lower = callout_content.lower()
    
        if str(total_meetings) not in callout_content:
            errors.append(f"[X] Statistics callout should mention {total_meetings} total meetings, but content is: '{callout_content}'")
        else:
            checks_passed.append(f"[C] Statistics callout should mention {total_meetings} total meetings, but content is: '{callout_content}'")
    
        if str(meetings_with_action_items) not in callout_content:
            errors.append(f"[X] Statistics callout should mention {meetings_with_action_items} meetings with action items, but content is: '{callout_content}'")
        else:
            checks_passed.append(f"[C] Statistics callout should mention {meetings_with_action_items} meetings with action items, but content is: '{callout_content}'")
    
        # Check average blocks (allow for rounding differences)
        avg_blocks_int = int(avg_blocks)
        avg_blocks_ceil = int(avg_blocks) + 1
        if str(avg_blocks_int) not in callout_content and str(avg_blocks_ceil) not in callout_content and str(avg_blocks) not in callout_content:
            errors.append(f"[X] Statistics callout should mention average blocks per meeting around {avg_blocks}, but content is: '{callout_content}'")
        else:
            checks_passed.append(f"[C] Statistics callout should mention average blocks per meeting around {avg_blocks}, but content is: '{callout_content}'")
    
        # 16. Validate meeting detail sections exist
        complete_meeting_sections = [s for s in meeting_sections if s["quote_idx"] != -1 and s["paragraph_idx"] != -1]
    
        if len(complete_meeting_sections) < len(meeting_children):
            errors.append(f"[X] Expected {len(meeting_children)} complete meeting sections (heading_3 + quote + paragraph), found {len(complete_meeting_sections)} complete sections out of {len(meeting_sections)} total sections")
        else:
            checks_passed.append(f"[C] Expected {len(meeting_children)} complete meeting sections (heading_3 + quote + paragraph), found {len(complete_meeting_sections)} complete sections out of {len(meeting_sections)} total sections")
    
        # 17. Validate each meeting section has correct structure
        for i, section in enumerate(complete_meeting_sections):
            heading_content = section["heading_content"]
        
            # Check heading has content (should have icon and meeting title)
            if len(heading_content.strip()) < 3:
                errors.append(f"[X] Meeting section {i+1} heading_3 is too short: '{heading_content}'")
            else:
                checks_passed.append(f"[C] Meeting section {i+1} heading_3 is too short: '{heading_content}'")
        
            # Validate quote block has date information
            quote_idx = section["quote_idx"]
            quote_block = summary_blocks[quote_idx]
            quote_content = quote_block.get("content", "").lower()
        
            if "meeting date:" not in quote_content and "date:" not in quote_content:
                errors.append(f"[X] Meeting section {i+1} quote block should mention 'Meeting date:', but content is: '{quote_block.get('content', '')}'")
            else:
                checks_passed.append(f"[C] Meeting section {i+1} quote block should mention 'Meeting date:', but content is: '{quote_block.get('content', '')}'")
        
            # Validate paragraph has block and todo counts
            paragraph_idx = section["paragraph_idx"]
            paragraph_block = summary_blocks[paragraph_idx]
            paragraph_content = paragraph_block.get("content", "").lower()
        
            if "content blocks:" not in paragraph_content:
                errors.append(f"[X] Meeting section {i+1} paragraph should mention 'Content blocks:', but content is: '{paragraph_block.get('content', '')}'")
            else:
                checks_passed.append(f"[C] Meeting section {i+1} paragraph should mention 'Content blocks:', but content is: '{paragraph_block.get('content', '')}'")
        
            if "todo items:" not in paragraph_content:
                errors.append(f"[X] Meeting section {i+1} paragraph should mention 'Todo items:', but content is: '{paragraph_block.get('content', '')}'")
            else:
                checks_passed.append(f"[C] Meeting section {i+1} paragraph should mention 'Todo items:', but content is: '{paragraph_block.get('content', '')}'")
    
        # ALL requirements met!
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: create-project-hub
# Description: Create comprehensive project tracking system with sections
# =============================================================================
def _validate_agent_create_project_hub(
    final_state_backend: Backend,
    final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate project hub creation."""
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Check Project Hub exists with folder icon and is favorited
    try:
        hub = _find_page_by_title(final_state_backend, "Project Hub")
        if not hub:
            errors.append("[X] Project Hub page not found")
        else:
            checks_passed.append("[C] Project Hub page found")

        if not _check_page_icon(hub, "📁"):
            errors.append("[X] Project Hub does not have folder icon (📁)")
        else:
            checks_passed.append("[C] Project Hub has folder icon (📁)")

        if not _check_page_is_favorite(hub):
            errors.append("[X] Project Hub is not marked as favorite")
        else:
            checks_passed.append("[C] Project Hub is marked as favorite")

        # 2. Check 3 required sections exist as children
        required_sections = ["Active Projects", "Project Templates", "Archived Projects"]
        success, error, found = _validate_page_structure(final_state_backend, hub, required_sections)
        if not success:
            errors.append(f"[X] Project Hub structure invalid: {error}")
        else:
            checks_passed.append(f"[C] Project Hub structure valid: {error}")

        # 3. Check Project Roadmap and Project Documentation are under Active Projects
        active_projects = _find_child_by_title(final_state_backend, hub, "Active Projects")
        if not active_projects:
            errors.append("[X] Active Projects section not found under Project Hub")
        else:
            checks_passed.append("[C] Active Projects section found under Project Hub")

        active_children = _get_child_pages(final_state_backend, active_projects.get("_id", ""))
        active_titles = [p.get("title", "").lower() for p in active_children]

        roadmap_found = any("roadmap" in t for t in active_titles)
        documentation_found = any("documentation" in t for t in active_titles)

        if not roadmap_found:
            errors.append("[X] Project Roadmap not moved under Active Projects")
        else:
            checks_passed.append("[C] Project Roadmap moved under Active Projects")
        if not documentation_found:
            errors.append("[X] Project Documentation not moved under Active Projects")
        else:
            checks_passed.append("[C] Project Documentation moved under Active Projects")

        # 4. Check project template exists under Project Templates with content
        templates_section = _find_child_by_title(final_state_backend, hub, "Project Templates")
        if templates_section:
            template_children = _get_child_pages(final_state_backend, templates_section.get("_id", ""))
            if len(template_children) < 1:
                errors.append("[X] No project template found under Project Templates section")
            else:
                checks_passed.append("[C] project template found under Project Templates section")

            # Check template has structured content (headings, todos)
            for template in template_children:
                template_blocks = _get_blocks_for_page(final_state_backend, template.get("_id", ""))
                has_heading = any(b.get("type", "").startswith("heading") for b in template_blocks)
                has_todo = any(b.get("type") == "todo" for b in template_blocks)
                if has_heading and has_todo:
                    break
            else:
                errors.append("[X] Project template lacks structured content (headings and todo items)")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: create-team-feedback-hub
# Description: Create centralized feedback and improvement system
# =============================================================================
def _validate_agent_create_team_feedback_hub(
    final_state_backend: Backend,
    final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate team feedback hub creation."""
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Check Team Feedback Hub exists with megaphone icon and is favorited
    try:
        hub = _find_page_by_title(final_state_backend, "Team Feedback Hub")
        if not hub:
            errors.append("[X] Team Feedback Hub page not found")
        else:
            checks_passed.append("[C] Team Feedback Hub page found")

        # Accept both megaphone icons (📢 or 📣)
        if not _check_page_icon(hub, "📢") and not _check_page_icon(hub, "📣"):
            errors.append("[X] Team Feedback Hub does not have megaphone icon (📢 or 📣)")
        else:
            checks_passed.append("[C] Team Feedback Hub has megaphone icon (📢 or 📣)")

        if not _check_page_is_favorite(hub):
            errors.append("[X] Team Feedback Hub is not marked as favorite")
        else:
            checks_passed.append("[C] Team Feedback Hub is marked as favorite")

        # 2. Check 3 required sections exist
        required_sections = ["Current Feedback", "Feature Requests", "Process Improvements"]
        success, error, found = _validate_page_structure(final_state_backend, hub, required_sections)
        if not success:
            errors.append(f"[X] Team Feedback Hub structure invalid: {error}")
        else:
            checks_passed.append(f"[C] Team Feedback Hub structure valid: {error}")

        # 3. Check Feature Requests page was moved under appropriate section
        feature_requests_section = _find_child_by_title(final_state_backend, hub, "Feature Requests")
        if feature_requests_section:
            fr_children = _get_child_pages(final_state_backend, feature_requests_section.get("_id", ""))
            # The original Feature Requests page should be moved here or section contains content
            if len(fr_children) < 1:
                # Check if the section itself has content blocks
                fr_blocks = _get_blocks_for_page(final_state_backend, feature_requests_section.get("_id", ""))
                if len(fr_blocks) < 1:
                    errors.append("[X] Feature Requests section has no content or child pages")
                else:
                    checks_passed.append("[C] Feature Requests section has content or child pages")

        # 4. Check for anonymous feedback and process suggestion pages with structured content
        def get_all_descendants(backend, parent_id):
            descendants = []
            children = _get_child_pages(backend, parent_id)
            for child in children:
                descendants.append(child)
                descendants.extend(get_all_descendants(backend, child.get("_id", "")))
            return descendants

        all_hub_pages = get_all_descendants(final_state_backend, hub.get("_id", ""))
        all_hub_titles = [p.get("title", "").lower() for p in all_hub_pages]

        has_anonymous = any("anonymous" in t or "feedback form" in t for t in all_hub_titles)
        has_process = any("process" in t or "suggestion" in t for t in all_hub_titles)

        if not has_anonymous:
            errors.append("[X] Anonymous feedback page not found under Team Feedback Hub")
        else:
            checks_passed.append("[C] Anonymous feedback page found under Team Feedback Hub")
        if not has_process:
            errors.append("[X] Process suggestion page not found under Team Feedback Hub")
        else:
            checks_passed.append("[C] Process suggestion page found under Team Feedback Hub")

        # Check for structured content in hub pages (headings, lists, todos, callouts)
        structured_pages = 0
        for page in all_hub_pages:
            page_blocks = _get_blocks_for_page(final_state_backend, page.get("_id", ""))
            has_heading = any(b.get("type", "").startswith("heading") for b in page_blocks)
            has_list = any(b.get("type") in ["bulletedList", "numberedList"] for b in page_blocks)
            has_todo = any(b.get("type") == "todo" for b in page_blocks)
            has_callout = any(b.get("type") == "callout" for b in page_blocks)

            if has_heading and (has_list or has_todo or has_callout):
                structured_pages += 1

        if structured_pages < 1:
            errors.append("[X] No pages with structured content (headings + lists/todos/callouts) found")
        else:
            checks_passed.append("[C] pages with structured content (headings + lists/todos/callouts) found")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: create-archive-management
# Description: Organize archived content with management page and categories
# =============================================================================
def _validate_agent_create_archive_management(
    final_state_backend: Backend,
    final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate archive management creation."""
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Check Archive Management page exists with warning icon and is favorited
    try:
        archive_mgmt = _find_page_by_title(final_state_backend, "Archive Management")
        if not archive_mgmt:
            errors.append("[X] Archive Management page not found")
        else:
            checks_passed.append("[C] Archive Management page found")

        if not _check_page_icon(archive_mgmt, "⚠️"):
            errors.append("[X] Archive Management does not have warning icon (⚠️)")
        else:
            checks_passed.append("[C] Archive Management has warning icon (⚠️)")

        if not _check_page_is_favorite(archive_mgmt):
            errors.append("[X] Archive Management is not marked as favorite")
        else:
            checks_passed.append("[C] Archive Management is marked as favorite")

        # 2. Check page has structured content (headings, paragraphs, todos)
        mgmt_blocks = _get_blocks_for_page(final_state_backend, archive_mgmt.get("_id", ""))

        has_headings = any(b.get("type", "").startswith("heading") for b in mgmt_blocks)
        has_paragraphs = any(b.get("type") == "paragraph" for b in mgmt_blocks)
        has_todos = any(b.get("type") == "todo" for b in mgmt_blocks)

        if not has_headings:
            errors.append("[X] Archive Management lacks heading blocks")
        else:
            checks_passed.append("[C] Archive Management lacks heading blocks")
        if not has_paragraphs:
            errors.append("[X] Archive Management lacks paragraph blocks")
        else:
            checks_passed.append("[C] Archive Management lacks paragraph blocks")
        if not has_todos:
            errors.append("[X] Archive Management lacks todo blocks for cleanup tasks")
        else:
            checks_passed.append("[C] Archive Management lacks todo blocks for cleanup tasks")

        # 3. Check that pages are organized under this management page
        archive_children = _get_child_pages(final_state_backend, archive_mgmt.get("_id", ""))

        if len(archive_children) < 1:
            errors.append("[X] No pages organized under Archive Management")
        else:
            checks_passed.append("[C] pages organized under Archive Management")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: create-team-resource-hub
# Description: Create comprehensive team resource center
# =============================================================================
def _validate_agent_create_team_resource_hub(
    final_state_backend: Backend,
    final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate team resource hub creation."""
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Check Team Resource Hub exists with team icon and is favorited
    try:
        hub = _find_page_by_title(final_state_backend, "Team Resource Hub")
        if not hub:
            errors.append("[X] Team Resource Hub page not found")
        else:
            checks_passed.append("[C] Team Resource Hub page found")

        if not _check_page_icon(hub, "👥"):
            errors.append("[X] Team Resource Hub does not have team icon (👥)")
        else:
            checks_passed.append("[C] Team Resource Hub has team icon (👥)")

        if not _check_page_is_favorite(hub):
            errors.append("[X] Team Resource Hub is not marked as favorite")
        else:
            checks_passed.append("[C] Team Resource Hub is marked as favorite")

        # 2. Check Team Directory was moved under hub
        hub_children = _get_child_pages(final_state_backend, hub.get("_id", ""))
        hub_child_titles = [p.get("title", "").lower() for p in hub_children]

        directory_found = any("directory" in t for t in hub_child_titles)
        if not directory_found:
            errors.append("[X] Team Directory not moved under Team Resource Hub")
        else:
            checks_passed.append("[C] Team Directory moved under Team Resource Hub")

        # 3. Check 3 new sub-pages created
        required_subpages = ["Team Guidelines", "Contact Information", "Meeting Schedules"]
        success, error, found = _validate_page_structure(final_state_backend, hub, required_subpages)
        if not success:
            errors.append(f"[X] Team Resource Hub missing sub-pages: {error}")
        else:
            checks_passed.append(f"[C] Team Resource Hub has sub-pages: {error}")

        # 4. Check Team Guidelines has structured content (headings, numbered lists, quotes)
        guidelines = _find_child_by_title(final_state_backend, hub, "Team Guidelines")
        if guidelines:
            guidelines_blocks = _get_blocks_for_page(final_state_backend, guidelines.get("_id", ""))

            has_headings = any(b.get("type", "").startswith("heading") for b in guidelines_blocks)
            has_numbered = any(b.get("type") == "numberedList" for b in guidelines_blocks)
            has_quote = any(b.get("type") == "quote" for b in guidelines_blocks)

            if not has_headings:
                errors.append("[X] Team Guidelines lacks heading blocks")
            else:
                checks_passed.append("[C] Team Guidelines lacks heading blocks")
            if not has_numbered:
                errors.append("[X] Team Guidelines lacks numbered list blocks")
            else:
                checks_passed.append("[C] Team Guidelines lacks numbered list blocks")
            if not has_quote:
                errors.append("[X] Team Guidelines lacks quote blocks for company values")
            else:
                checks_passed.append("[C] Team Guidelines lacks quote blocks for company values")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: create-templates-collection
# Description: Clean up and organize template collection with master template
# =============================================================================
def _validate_agent_create_templates_collection(
    final_state_backend: Backend,
    final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate templates collection creation."""
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Check Templates Collection exists with file cabinet icon and is favorited
    try:
        collection = _find_page_by_title(final_state_backend, "Templates Collection")
        if not collection:
            errors.append("[X] Templates Collection page not found")
        else:
            checks_passed.append("[C] Templates Collection page found")

        if not _check_page_icon(collection, "🗄️"):
            errors.append("[X] Templates Collection does not have file cabinet icon (🗄️)")
        else:
            checks_passed.append("[C] Templates Collection has file cabinet icon (🗄️)")

        if not _check_page_is_favorite(collection):
            errors.append("[X] Templates Collection is not marked as favorite")
        else:
            checks_passed.append("[C] Templates Collection is marked as favorite")

        # 2. Check Master Project Template exists under collection
        collection_children = _get_child_pages(final_state_backend, collection.get("_id", ""))
        master_template = None
        for child in collection_children:
            if "master" in child.get("title", "").lower() and "template" in child.get("title", "").lower():
                master_template = child
                break

        if not master_template:
            errors.append("[X] Master Project Template not found under Templates Collection")
        else:
            checks_passed.append("[C] Master Project Template found under Templates Collection")

        # 2b. Check Master Project Template has briefcase icon
        if not _check_page_icon(master_template, "💼"):
            errors.append("[X] Master Project Template does not have briefcase icon (💼)")
        else:
            checks_passed.append("[C] Master Project Template has briefcase icon (💼)")

        # 3. Check Master Project Template has comprehensive structure
        master_blocks = _get_blocks_for_page(final_state_backend, master_template.get("_id", ""))

        has_heading = any(b.get("type", "").startswith("heading") for b in master_blocks)
        has_paragraph = any(b.get("type") == "paragraph" for b in master_blocks)
        has_numbered = any(b.get("type") == "numberedList" for b in master_blocks)
        has_todo = any(b.get("type") == "todo" for b in master_blocks)
        has_bulleted = any(b.get("type") == "bulletedList" for b in master_blocks)
        has_code = any(b.get("type") == "code" for b in master_blocks)

        if not has_heading:
            errors.append("[X] Master Project Template lacks heading blocks")
        else:
            checks_passed.append("[C] Master Project Template lacks heading blocks")
        if not has_paragraph:
            errors.append("[X] Master Project Template lacks paragraph for project overview")
        else:
            checks_passed.append("[C] Master Project Template lacks paragraph for project overview")
        if not has_numbered:
            errors.append("[X] Master Project Template lacks numbered list for goals")
        else:
            checks_passed.append("[C] Master Project Template lacks numbered list for goals")
        if not has_todo:
            errors.append("[X] Master Project Template lacks todo items for timeline")
        else:
            checks_passed.append("[C] Master Project Template lacks todo items for timeline")
        if not has_bulleted:
            errors.append("[X] Master Project Template lacks bulleted list for resources")
        else:
            checks_passed.append("[C] Master Project Template lacks bulleted list for resources")
        if not has_code:
            errors.append("[X] Master Project Template lacks code block for technical notes")
        else:
            checks_passed.append("[C] Master Project Template lacks code block for technical notes")

        # 4. Check at least 1 existing template plus master are under collection
        # (relaxed from 4 to 2 - master template + at least 1 moved template)
        template_count = len(collection_children)
        if template_count < 2:  # master + at least 1 existing
            errors.append(f"[X] Templates Collection has only {template_count} templates, need at least 2 (master + 1 existing)")
        else:
            checks_passed.append(f"[C] Templates Collection has only {template_count} templates, need at least 2 (master + 1 existing)")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: create-knowledge-base
# Description: Build knowledge sharing system with structured sub-pages
# =============================================================================
def _validate_agent_create_knowledge_base(
    final_state_backend: Backend,
    final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate knowledge base creation."""
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Check Knowledge Base exists with brain icon and is favorited
    try:
        kb = _find_page_by_title(final_state_backend, "Knowledge Base")
        if not kb:
            errors.append("[X] Knowledge Base page not found")
        else:
            checks_passed.append("[C] Knowledge Base page found")

        if not _check_page_icon(kb, "🧠"):
            errors.append("[X] Knowledge Base does not have brain icon (🧠)")
        else:
            checks_passed.append("[C] Knowledge Base has brain icon (🧠)")

        if not _check_page_is_favorite(kb):
            errors.append("[X] Knowledge Base is not marked as favorite")
        else:
            checks_passed.append("[C] Knowledge Base is marked as favorite")

        # 2. Check 3 required sub-pages exist
        required_subpages = ["Best Practices", "Lessons Learned", "FAQ"]
        success, error, found = _validate_page_structure(final_state_backend, kb, required_subpages)
        if not success:
            errors.append(f"[X] Knowledge Base structure invalid: {error}")
        else:
            checks_passed.append(f"[C] Knowledge Base structure valid: {error}")

        # 3. Check Best Practices has headings and bulleted lists
        best_practices = _find_child_by_title(final_state_backend, kb, "Best Practices")
        if best_practices:
            bp_blocks = _get_blocks_for_page(final_state_backend, best_practices.get("_id", ""))
            has_heading = any(b.get("type", "").startswith("heading") for b in bp_blocks)
            has_bulleted = any(b.get("type") == "bulletedList" for b in bp_blocks)
            if not has_heading:
                errors.append("[X] Best Practices lacks heading blocks")
            else:
                checks_passed.append("[C] Best Practices lacks heading blocks")
            if not has_bulleted:
                errors.append("[X] Best Practices lacks bulleted list blocks")
            else:
                checks_passed.append("[C] Best Practices lacks bulleted list blocks")

        # 4. Check Lessons Learned has quote blocks
        lessons_learned = _find_child_by_title(final_state_backend, kb, "Lessons Learned")
        if lessons_learned:
            ll_blocks = _get_blocks_for_page(final_state_backend, lessons_learned.get("_id", ""))
            has_quote = any(b.get("type") == "quote" for b in ll_blocks)
            if not has_quote:
                errors.append("[X] Lessons Learned lacks quote blocks")
            else:
                checks_passed.append("[C] Lessons Learned lacks quote blocks")

        # 5. Check FAQ has code block
        faq = _find_child_by_title(final_state_backend, kb, "FAQ")
        if faq:
            faq_blocks = _get_blocks_for_page(final_state_backend, faq.get("_id", ""))
            has_code = any(b.get("type") == "code" for b in faq_blocks)
            if not has_code:
                errors.append("[X] FAQ lacks code block")
            else:
                checks_passed.append("[C] FAQ lacks code block")

        # 6. Check total blocks >= 8
        total_blocks = 0
        kb_blocks = _get_blocks_for_page(final_state_backend, kb.get("_id", ""))
        total_blocks += len(kb_blocks)
        for subpage_title in required_subpages:
            subpage = _find_child_by_title(final_state_backend, kb, subpage_title)
            if subpage:
                subpage_blocks = _get_blocks_for_page(final_state_backend, subpage.get("_id", ""))
                total_blocks += len(subpage_blocks)

        if total_blocks < 8:
            errors.append(f"[X] Total blocks ({total_blocks}) is less than required 8")
        else:
            checks_passed.append(f"[C] Total blocks ({total_blocks}) is less than required 8")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: create-engineering-knowledge-base
# Description: Create knowledge base from existing engineering content
# =============================================================================
def _validate_agent_create_engineering_knowledge_base(
    final_state_backend: Backend,
    final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate engineering knowledge base creation."""
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Check Engineering Knowledge Base exists with gear icon
    try:
        kb = _find_page_by_title(final_state_backend, "Engineering Knowledge Base")
        if not kb:
            errors.append("[X] Engineering Knowledge Base page not found")
        else:
            checks_passed.append("[C] Engineering Knowledge Base page found")

        if not _check_page_icon(kb, "⚙️"):
            errors.append("[X] Engineering Knowledge Base does not have gear icon (⚙️)")
        else:
            checks_passed.append("[C] Engineering Knowledge Base has gear icon (⚙️)")

        # 2. Check page has 3 section headings (inline content, not child pages)
        kb_blocks = _get_blocks_for_page(final_state_backend, kb.get("_id", ""))
        heading_contents = [b.get("content", "").lower() for b in kb_blocks if b.get("type", "").startswith("heading")]

        required_sections = ["getting started", "best practices", "troubleshooting"]
        for section in required_sections:
            if not any(section in h for h in heading_contents):
                errors.append(f"[X] Missing section heading for '{section}'")
            else:
                checks_passed.append(f"[C] has section heading for '{section}'")

        # 3. Check page has required content types: headings, numbered lists, code, callouts
        has_heading = any(b.get("type", "").startswith("heading") for b in kb_blocks)
        has_numbered = any(b.get("type") == "numberedList" for b in kb_blocks)
        has_code = any(b.get("type") == "code" for b in kb_blocks)
        has_callout = any(b.get("type") == "callout" for b in kb_blocks)

        if not has_heading:
            errors.append("[X] Engineering Knowledge Base lacks heading blocks")
        else:
            checks_passed.append("[C] Engineering Knowledge Base lacks heading blocks")
        if not has_numbered:
            errors.append("[X] Engineering Knowledge Base lacks numbered list blocks")
        else:
            checks_passed.append("[C] Engineering Knowledge Base lacks numbered list blocks")
        if not has_code:
            errors.append("[X] Engineering Knowledge Base lacks code blocks")
        else:
            checks_passed.append("[C] Engineering Knowledge Base lacks code blocks")
        if not has_callout:
            errors.append("[X] Engineering Knowledge Base lacks callout blocks")
        else:
            checks_passed.append("[C] Engineering Knowledge Base lacks callout blocks")

        # 4. Check API or Bug pages are children of knowledge base
        kb_children = _get_child_pages(final_state_backend, kb.get("_id", ""))
        kb_child_titles = [p.get("title", "").lower() for p in kb_children]
        has_api_or_bug = any("api" in t or "bug" in t for t in kb_child_titles)

        if not has_api_or_bug:
            errors.append("[X] No API or Bug pages moved under Engineering Knowledge Base")
        else:
            checks_passed.append("[C] API or Bug pages moved under Engineering Knowledge Base")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: create-weekly-onboarding-curriculum
# Description: Create structured 3-week onboarding curriculum with weekly sub-pages
# =============================================================================
def _validate_weekly_onboarding_curriculum(
    final_state_backend: Backend,
    final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate team onboarding guide creation."""
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Check Team Onboarding Guide exists with wave icon and is favorited
    try:
        guide = _find_page_by_title(final_state_backend, "Team Onboarding Guide")
        if not guide:
            errors.append("[X] Team Onboarding Guide page not found")
        else:
            checks_passed.append("[C] Team Onboarding Guide page found")

        if not _check_page_icon(guide, "👋"):
            errors.append("[X] Team Onboarding Guide does not have wave icon (👋)")
        else:
            checks_passed.append("[C] Team Onboarding Guide has wave icon (👋)")

        if not _check_page_is_favorite(guide):
            errors.append("[X] Team Onboarding Guide is not marked as favorite")
        else:
            checks_passed.append("[C] Team Onboarding Guide is marked as favorite")

        # 2. Check main page has heading1 and paragraph
        guide_blocks = _get_blocks_for_page(final_state_backend, guide.get("_id", ""))
        has_heading1 = any(b.get("type") == "heading1" for b in guide_blocks)
        has_paragraph = any(b.get("type") == "paragraph" for b in guide_blocks)

        if not has_heading1:
            errors.append("[X] Team Onboarding Guide lacks heading1 block")
        else:
            checks_passed.append("[C] Team Onboarding Guide lacks heading1 block")
        if not has_paragraph:
            errors.append("[X] Team Onboarding Guide lacks overview paragraph")
        else:
            checks_passed.append("[C] Team Onboarding Guide lacks overview paragraph")

        # 3. Check exactly 3 sub-pages with correct titles
        required_weeks = ["Week 1", "Week 2", "Week 3"]
        guide_children = _get_child_pages(final_state_backend, guide.get("_id", ""))

        if len(guide_children) != 3:
            errors.append(f"[X] Expected 3 sub-pages, found {len(guide_children)}")
        else:
            checks_passed.append(f"[C] Found 3 sub-pages as expected")

        for week in required_weeks:
            found = any(week.lower() in p.get("title", "").lower() for p in guide_children)
            if not found:
                errors.append(f"[X] Sub-page for '{week}' not found")
            else:
                checks_passed.append(f"[C] Sub-page for '{week}' found")

        # 4. Check each sub-page has heading and quote block
        for child in guide_children:
            child_blocks = _get_blocks_for_page(final_state_backend, child.get("_id", ""))
            has_heading = any(b.get("type", "").startswith("heading") for b in child_blocks)
            has_quote = any(b.get("type") == "quote" for b in child_blocks)

            if not has_heading:
                errors.append(f"[X] Sub-page '{child.get('title')}' lacks heading block")
            else:
                checks_passed.append(f"[C] Sub-page '{child.get('title')}' lacks heading block")
            if not has_quote:
                errors.append(f"[X] Sub-page '{child.get('title')}' lacks quote block")
            else:
                checks_passed.append(f"[C] Sub-page '{child.get('title')}' lacks quote block")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: create-knowledge-hub
# Description: Create knowledge hub with Engineering Wiki and companion pages
# =============================================================================
def _validate_agent_create_knowledge_hub(
    final_state_backend: Backend,
    final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate knowledge hub creation."""
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Check Knowledge Hub exists with brain icon and is favorited
    try:
        hub = _find_page_by_title(final_state_backend, "Knowledge Hub")
        if not hub:
            errors.append("[X] Knowledge Hub page not found")
        else:
            checks_passed.append("[C] Knowledge Hub page found")

        if not _check_page_icon(hub, "🧠"):
            errors.append("[X] Knowledge Hub does not have brain icon (🧠)")
        else:
            checks_passed.append("[C] Knowledge Hub has brain icon (🧠)")

        if not _check_page_is_favorite(hub):
            errors.append("[X] Knowledge Hub is not marked as favorite")
        else:
            checks_passed.append("[C] Knowledge Hub is marked as favorite")

        # 2. Check Engineering Wiki is child of hub
        hub_children = _get_child_pages(final_state_backend, hub.get("_id", ""))
        hub_child_titles = [p.get("title", "").lower() for p in hub_children]

        wiki_found = any("engineering wiki" in t for t in hub_child_titles)
        if not wiki_found:
            errors.append("[X] Engineering Wiki not moved under Knowledge Hub")
        else:
            checks_passed.append("[C] Engineering Wiki moved under Knowledge Hub")

        # 3. Check Quick Reference Guide exists with code blocks and dividers
        quick_ref = _find_child_by_title(final_state_backend, hub, "Quick Reference Guide")
        if not quick_ref:
            errors.append("[X] Quick Reference Guide not found under Knowledge Hub")
        else:
            checks_passed.append("[C] Quick Reference Guide found under Knowledge Hub")

        qr_blocks = _get_blocks_for_page(final_state_backend, quick_ref.get("_id", ""))
        has_code = any(b.get("type") == "code" for b in qr_blocks)
        has_divider = any(b.get("type") == "divider" for b in qr_blocks)

        if not has_code:
            errors.append("[X] Quick Reference Guide lacks code blocks")
        else:
            checks_passed.append("[C] Quick Reference Guide lacks code blocks")
        if not has_divider:
            errors.append("[X] Quick Reference Guide lacks divider blocks")
        else:
            checks_passed.append("[C] Quick Reference Guide lacks divider blocks")

        # 4. Check Learning Resources exists with bulleted lists and dividers
        learning = _find_child_by_title(final_state_backend, hub, "Learning Resources")
        if not learning:
            errors.append("[X] Learning Resources not found under Knowledge Hub")
        else:
            checks_passed.append("[C] Learning Resources found under Knowledge Hub")

        lr_blocks = _get_blocks_for_page(final_state_backend, learning.get("_id", ""))
        has_bulleted = any(b.get("type") == "bulletedList" for b in lr_blocks)
        has_divider_lr = any(b.get("type") == "divider" for b in lr_blocks)

        if not has_bulleted:
            errors.append("[X] Learning Resources lacks bulleted list blocks")
        else:
            checks_passed.append("[C] Learning Resources lacks bulleted list blocks")
        if not has_divider_lr:
            errors.append("[X] Learning Resources lacks divider blocks")
        else:
            checks_passed.append("[C] Learning Resources lacks divider blocks")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: create-product-management-hub
# Description: Set up product management workspace with sections and templates
# =============================================================================
def _validate_agent_create_product_management_hub(
    final_state_backend: Backend,
    final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate product management hub creation."""
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Check Product Management Hub exists with target icon and is favorited
    try:
        hub = _find_page_by_title(final_state_backend, "Product Management Hub")
        if not hub:
            errors.append("[X] Product Management Hub page not found")
        else:
            checks_passed.append("[C] Product Management Hub page found")

        if not _check_page_icon(hub, "🎯"):
            errors.append("[X] Product Management Hub does not have target icon (🎯)")
        else:
            checks_passed.append("[C] Product Management Hub has target icon (🎯)")

        if not _check_page_is_favorite(hub):
            errors.append("[X] Product Management Hub is not marked as favorite")
        else:
            checks_passed.append("[C] Product Management Hub is marked as favorite")

        # 2. Check hub has 3 headings, 3 bulleted lists, 2+ todos, 1 callout
        hub_blocks = _get_blocks_for_page(final_state_backend, hub.get("_id", ""))

        heading_count = sum(1 for b in hub_blocks if b.get("type", "").startswith("heading"))
        bulleted_count = sum(1 for b in hub_blocks if b.get("type") == "bulletedList")
        todo_count = sum(1 for b in hub_blocks if b.get("type") == "todo")
        callout_count = sum(1 for b in hub_blocks if b.get("type") == "callout")

        if heading_count < 3:
            errors.append(f"[X] Product Management Hub has {heading_count} headings, expected at least 3")
        else:
            checks_passed.append(f"[C] Product Management Hub has {heading_count} headings, expected at least 3")
        if bulleted_count < 3:
            errors.append(f"[X] Product Management Hub has {bulleted_count} bulleted lists, expected at least 3")
        else:
            checks_passed.append(f"[C] Product Management Hub has {bulleted_count} bulleted lists, expected at least 3")
        if todo_count < 2:
            errors.append(f"[X] Product Management Hub has {todo_count} todos, expected at least 2")
        else:
            checks_passed.append(f"[C] Product Management Hub has {todo_count} todos, expected at least 2")
        if callout_count < 1:
            errors.append("[X] Product Management Hub lacks callout block")
        else:
            checks_passed.append("[C] Product Management Hub lacks callout block")

        # 3. Check Feature Template exists (duplicated from Feature Requests)
        feature_template = _find_page_by_title(final_state_backend, "Feature Template")
        if not feature_template:
            errors.append("[X] Feature Template not found (should be duplicated from Feature Requests)")
        else:
            checks_passed.append("[C] Feature Template found (should be duplicated from Feature Requests)")

        # 4. Check if pages are organized under product-related parent (optional but preferred)
        # Relaxed: only check if a product parent exists and pages are organized
        hub_parent_id = hub.get("parentId")
        template_parent_id = feature_template.get("parentId")

        # Find product-related pages (pages with "product" in title, excluding the hub itself)
        all_product_pages_result = final_state_backend.query({
            "collection": "pages",
            "filter": {"title": {"$regex": "product", "$options": "i"}}
        })
        all_product_pages = all_product_pages_result if isinstance(all_product_pages_result, list) else []
        product_pages = [p for p in all_product_pages if p.get("_id") != hub.get("_id")]

        # If product pages exist, check organization; otherwise accept any valid structure
        if product_pages:
            product_page_ids = [p.get("_id") for p in product_pages]
            hub_under_product = hub_parent_id in product_page_ids
            template_under_product = template_parent_id in product_page_ids

            if hub_under_product and template_under_product:
                return TaskScore(
                    score=1.0 if len(errors) == 0 else 0.0,
                    metadata=ScoreMetadata(
                        success_accumulator=list(dict.fromkeys(checks_passed)),
                        error_accumulator=list(dict.fromkeys(errors)),
                    )
                )
            elif hub_under_product or template_under_product:
                return TaskScore(
                    score=1.0 if len(errors) == 0 else 0.0,
                    metadata=ScoreMetadata(
                        success_accumulator=list(dict.fromkeys(checks_passed)),
                        error_accumulator=list(dict.fromkeys(errors)),
                    )
                )

        # Accept if hub and template exist with proper content even without product parent
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: create-training-library
# Description: Create training materials library with templates and modules
# =============================================================================
def _validate_agent_create_training_library(
    final_state_backend: Backend,
    final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate training library creation."""
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Check Training Library exists with graduation cap icon
    try:
        library = _find_page_by_title(final_state_backend, "Training Library")
        if not library:
            errors.append("[X] Training Library page not found")
        else:
            checks_passed.append("[C] Training Library page found")

        if not _check_page_icon(library, "🎓"):
            errors.append("[X] Training Library does not have graduation cap icon (🎓)")
        else:
            checks_passed.append("[C] Training Library has graduation cap icon (🎓)")

        # 2. Check Training Session Template exists under library
        library_children = _get_child_pages(final_state_backend, library.get("_id", ""))
        library_child_titles = [p.get("title", "").lower() for p in library_children]

        template_found = any("training session template" in t for t in library_child_titles)
        if not template_found:
            errors.append("[X] Training Session Template not found under Training Library")
        else:
            checks_passed.append("[C] Training Session Template found under Training Library")

        # 3. Check Onboarding Modules and Skills Assessment exist under library
        onboarding_found = any("onboarding" in t for t in library_child_titles)
        skills_found = any("skills" in t or "assessment" in t for t in library_child_titles)

        if not onboarding_found:
            errors.append("[X] Onboarding Modules not found under Training Library")
        else:
            checks_passed.append("[C] Onboarding Modules found under Training Library")
        if not skills_found:
            errors.append("[X] Skills Assessment not found under Training Library")
        else:
            checks_passed.append("[C] Skills Assessment found under Training Library")

        # 4. Check library has structured index with headings and bullet points
        library_blocks = _get_blocks_for_page(final_state_backend, library.get("_id", ""))
        has_heading = any(b.get("type", "").startswith("heading") for b in library_blocks)
        has_bulleted = any(b.get("type") == "bulletedList" for b in library_blocks)

        if not has_heading:
            errors.append("[X] Training Library lacks heading blocks for index")
        else:
            checks_passed.append("[C] Training Library lacks heading blocks for index")
        if not has_bulleted:
            errors.append("[X] Training Library lacks bulleted list blocks for index")
        else:
            checks_passed.append("[C] Training Library lacks bulleted list blocks for index")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: create-team-handbook
# Description: Create comprehensive team handbook with detailed sub-pages
# =============================================================================
def _validate_agent_create_team_handbook(
    final_state_backend: Backend,
    final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate team handbook creation."""
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Check Team Handbook exists with handshake icon and is favorited
    try:
        handbook = _find_page_by_title(final_state_backend, "Team Handbook")
        if not handbook:
            errors.append("[X] Team Handbook page not found")
        else:
            checks_passed.append("[C] Team Handbook page found")

        if not _check_page_icon(handbook, "🤝"):
            errors.append("[X] Team Handbook does not have handshake icon (🤝)")
        else:
            checks_passed.append("[C] Team Handbook has handshake icon (🤝)")

        if not _check_page_is_favorite(handbook):
            errors.append("[X] Team Handbook is not marked as favorite")
        else:
            checks_passed.append("[C] Team Handbook is marked as favorite")

        # 2. Check main page has heading, paragraph, and numbered list (TOC)
        handbook_blocks = _get_blocks_for_page(final_state_backend, handbook.get("_id", ""))
        has_heading = any(b.get("type", "").startswith("heading") for b in handbook_blocks)
        has_paragraph = any(b.get("type") == "paragraph" for b in handbook_blocks)
        has_numbered = any(b.get("type") == "numberedList" for b in handbook_blocks)

        if not has_heading:
            errors.append("[X] Team Handbook lacks welcome heading")
        else:
            checks_passed.append("[C] Team Handbook lacks welcome heading")
        if not has_paragraph:
            errors.append("[X] Team Handbook lacks introduction paragraph")
        else:
            checks_passed.append("[C] Team Handbook lacks introduction paragraph")
        if not has_numbered:
            errors.append("[X] Team Handbook lacks numbered list for table of contents")
        else:
            checks_passed.append("[C] Team Handbook lacks numbered list for table of contents")

        # 3. Check exactly 4 child pages
        handbook_children = _get_child_pages(final_state_backend, handbook.get("_id", ""))
        if len(handbook_children) != 4:
            errors.append(f"[X] Expected 4 child pages, found {len(handbook_children)}")
        else:
            checks_passed.append(f"[C] Found 4 child pages as expected")

        # 4. Check Communication Guidelines has 2 headings, paragraphs, bulleted lists
        comm = _find_child_by_title(final_state_backend, handbook, "Communication Guidelines")
        if comm:
            comm_blocks = _get_blocks_for_page(final_state_backend, comm.get("_id", ""))
            heading_count = sum(1 for b in comm_blocks if b.get("type", "").startswith("heading"))
            has_paragraph = any(b.get("type") == "paragraph" for b in comm_blocks)
            has_bulleted = any(b.get("type") == "bulletedList" for b in comm_blocks)

            if heading_count < 2:
                errors.append("[X] Communication Guidelines has fewer than 2 headings")
            else:
                checks_passed.append("[C] Communication Guidelines has fewer than 2 headings")
            if not has_paragraph:
                errors.append("[X] Communication Guidelines lacks paragraph blocks")
            else:
                checks_passed.append("[C] Communication Guidelines lacks paragraph blocks")
            if not has_bulleted:
                errors.append("[X] Communication Guidelines lacks bulleted list blocks")
            else:
                checks_passed.append("[C] Communication Guidelines lacks bulleted list blocks")

        # 5. Check Meeting Protocols has heading, numbered lists, quote block
        meeting = _find_child_by_title(final_state_backend, handbook, "Meeting Protocols")
        if meeting:
            meeting_blocks = _get_blocks_for_page(final_state_backend, meeting.get("_id", ""))
            has_heading = any(b.get("type", "").startswith("heading") for b in meeting_blocks)
            has_numbered = any(b.get("type") == "numberedList" for b in meeting_blocks)
            has_quote = any(b.get("type") == "quote" for b in meeting_blocks)

            if not has_heading:
                errors.append("[X] Meeting Protocols lacks heading blocks")
            else:
                checks_passed.append("[C] Meeting Protocols lacks heading blocks")
            if not has_numbered:
                errors.append("[X] Meeting Protocols lacks numbered list blocks")
            else:
                checks_passed.append("[C] Meeting Protocols lacks numbered list blocks")
            if not has_quote:
                errors.append("[X] Meeting Protocols lacks quote block")
            else:
                checks_passed.append("[C] Meeting Protocols lacks quote block")

        # 6. Check Code Standards has code block, heading, todo checklist
        code_std = _find_child_by_title(final_state_backend, handbook, "Code Standards")
        if code_std:
            code_blocks = _get_blocks_for_page(final_state_backend, code_std.get("_id", ""))
            has_code = any(b.get("type") == "code" for b in code_blocks)
            has_heading = any(b.get("type", "").startswith("heading") for b in code_blocks)
            has_todo = any(b.get("type") == "todo" for b in code_blocks)

            if not has_code:
                errors.append("[X] Code Standards lacks code block")
            else:
                checks_passed.append("[C] Code Standards lacks code block")
            if not has_heading:
                errors.append("[X] Code Standards lacks heading blocks")
            else:
                checks_passed.append("[C] Code Standards lacks heading blocks")
            if not has_todo:
                errors.append("[X] Code Standards lacks todo checklist")
            else:
                checks_passed.append("[C] Code Standards lacks todo checklist")

        # 7. Check Onboarding Checklist is favorited
        onboarding = _find_child_by_title(final_state_backend, handbook, "Onboarding Checklist")
        if onboarding:
            if not _check_page_is_favorite(onboarding):
                errors.append("[X] Onboarding Checklist is not marked as favorite")
            else:
                checks_passed.append("[C] Onboarding Checklist is marked as favorite")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: create-design-system-docs
# Description: Create comprehensive design system documentation
# =============================================================================
def _validate_agent_create_design_system_docs(
    final_state_backend: Backend,
    final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate design system documentation creation."""
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Check Design System v2.0 exists with design icon and is archived
    try:
        v2 = _find_page_by_title(final_state_backend, "Design System v2.0")
        if not v2:
            errors.append("[X] Design System v2.0 not found (should be duplicated)")
        else:
            checks_passed.append("[C] Design System v2.0 found (should be duplicated)")

        if not _check_page_icon(v2, "🎨"):
            errors.append("[X] Design System v2.0 does not have design icon (🎨)")
        else:
            checks_passed.append("[C] Design System v2.0 has design icon (🎨)")

        if not _check_page_is_archived(v2):
            errors.append("[X] Design System v2.0 is not archived")
        else:
            checks_passed.append("[C] Design System v2.0 is archived")

        # 2. Check original Design System exists and is favorited
        design_system = _find_page_by_title(final_state_backend, "Design System")
        if not design_system:
            errors.append("[X] Original Design System page not found")
        else:
            checks_passed.append("[C] Original Design System page found")

        if not _check_page_is_favorite(design_system):
            errors.append("[X] Design System is not marked as favorite")
        else:
            checks_passed.append("[C] Design System is marked as favorite")

        # 3. Check 3 subpages with correct icons under original Design System
        component_lib = _find_child_by_title(final_state_backend, design_system, "Component Library")
        if not component_lib:
            errors.append("[X] Component Library not found under Design System")
        else:
            checks_passed.append("[C] Component Library found under Design System")
        if not _check_page_icon(component_lib, "🧩"):
            errors.append("[X] Component Library does not have puzzle piece icon (🧩)")
        else:
            checks_passed.append("[C] Component Library has puzzle piece icon (🧩)")

        brand_guidelines = _find_child_by_title(final_state_backend, design_system, "Brand Guidelines")
        if not brand_guidelines:
            errors.append("[X] Brand Guidelines not found under Design System")
        else:
            checks_passed.append("[C] Brand Guidelines found under Design System")
        if not _check_page_icon(brand_guidelines, "🎨"):
            errors.append("[X] Brand Guidelines does not have palette icon (🎨)")
        else:
            checks_passed.append("[C] Brand Guidelines has palette icon (🎨)")

        usage_examples = _find_child_by_title(final_state_backend, design_system, "Usage Examples")
        if not usage_examples:
            errors.append("[X] Usage Examples not found under Design System")
        else:
            checks_passed.append("[C] Usage Examples found under Design System")
        if not _check_page_icon(usage_examples, "👁️"):
            errors.append("[X] Usage Examples does not have eye icon (👁️)")
        else:
            checks_passed.append("[C] Usage Examples has eye icon (👁️)")

        # 4. Check Component Library has headings, paragraphs, and todos
        cl_blocks = _get_blocks_for_page(final_state_backend, component_lib.get("_id", ""))
        has_heading = any(b.get("type", "").startswith("heading") for b in cl_blocks)
        has_paragraph = any(b.get("type") == "paragraph" for b in cl_blocks)
        has_todo = any(b.get("type") == "todo" for b in cl_blocks)

        if not has_heading:
            errors.append("[X] Component Library lacks heading blocks")
        else:
            checks_passed.append("[C] Component Library lacks heading blocks")
        if not has_paragraph:
            errors.append("[X] Component Library lacks paragraph blocks")
        else:
            checks_passed.append("[C] Component Library lacks paragraph blocks")
        if not has_todo:
            errors.append("[X] Component Library lacks todo blocks")
        else:
            checks_passed.append("[C] Component Library lacks todo blocks")

        # 5. Check Brand Guidelines has code blocks and bulleted lists
        bg_blocks = _get_blocks_for_page(final_state_backend, brand_guidelines.get("_id", ""))
        has_code = any(b.get("type") == "code" for b in bg_blocks)
        has_bulleted = any(b.get("type") == "bulletedList" for b in bg_blocks)

        if not has_code:
            errors.append("[X] Brand Guidelines lacks code blocks")
        else:
            checks_passed.append("[C] Brand Guidelines lacks code blocks")
        if not has_bulleted:
            errors.append("[X] Brand Guidelines lacks bulleted list blocks")
        else:
            checks_passed.append("[C] Brand Guidelines lacks bulleted list blocks")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: create-meeting-action-items-hub
# Description: Analyze meeting pages and create hub with unchecked action items
# =============================================================================
def _validate_agent_create_meeting_action_items_hub(
    final_state_backend: Backend,
    final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate meeting action items hub creation."""
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Check Meeting Action Items Hub exists with pin icon
    try:
        hub = _find_page_by_title(final_state_backend, "Meeting Action Items Hub")
        if not hub:
            errors.append("[X] Meeting Action Items Hub page not found")
        else:
            checks_passed.append("[C] Meeting Action Items Hub page found")

        if not _check_page_icon(hub, "📌"):
            errors.append("[X] Meeting Action Items Hub does not have pin icon (📌)")
        else:
            checks_passed.append("[C] Meeting Action Items Hub has pin icon (📌)")

        # 2. Find all meeting pages and count todos per page
        all_meeting_pages_result = final_state_backend.query({
            "collection": "pages",
            "filter": {"title": {"$regex": "meeting", "$options": "i"}}
        })
        all_meeting_pages = all_meeting_pages_result if isinstance(all_meeting_pages_result, list) else []
        meeting_pages = [p for p in all_meeting_pages if p.get("_id") != hub.get("_id")]
        if not meeting_pages:
            errors.append("[X] No meeting pages found to analyze")
        else:
            checks_passed.append("[C] meeting pages found to analyze")

        # Count todos for each meeting page
        meeting_todo_counts = []
        for meeting in meeting_pages:
            page_blocks = _get_blocks_for_page(final_state_backend, meeting.get("_id", ""))
            todo_count = sum(1 for b in page_blocks if b.get("type") == "todo")
            meeting_todo_counts.append((meeting, todo_count))

        # Find meeting with most todos
        if not meeting_todo_counts:
            errors.append("[X] Could not analyze meeting pages for todos")
        else:
            checks_passed.append("[C] Could analyze meeting pages for todos")

        source_meeting, max_todos = max(meeting_todo_counts, key=lambda x: x[1])
        if max_todos == 0:
            errors.append("[X] No meeting page has any todo blocks")
        else:
            checks_passed.append("[C] meeting page has any todo blocks")

        # 3. Check hub is sibling to source meeting (same parentId)
        hub_parent = hub.get("parentId")
        source_parent = source_meeting.get("parentId")

        if hub_parent != source_parent:
            errors.append(f"[X] Hub is not a sibling to the meeting page with most todos ('{source_meeting.get('title')}')")
        else:
            checks_passed.append(f"[C] Hub is a sibling to the meeting page with most todos ('{source_meeting.get('title')}')")

        # 4. Check hub has heading containing source page title
        hub_blocks = _get_blocks_for_page(final_state_backend, hub.get("_id", ""))
        source_title = source_meeting.get("title", "").lower()

        heading_blocks = [b for b in hub_blocks if b.get("type", "").startswith("heading")]
        has_title_heading = any(source_title in b.get("content", "").lower() for b in heading_blocks)

        if not has_title_heading:
            errors.append(f"[X] Hub lacks heading containing source page title ('{source_meeting.get('title')}')")
        else:
            checks_passed.append(f"[C] Hub lacks heading containing source page title ('{source_meeting.get('title')}')")

        # 5. Check hub contains unchecked todo items
        source_blocks = _get_blocks_for_page(final_state_backend, source_meeting.get("_id", ""))
        source_unchecked = [b for b in source_blocks if b.get("type") == "todo" and not b.get("properties", {}).get("checked", False)]

        hub_todos = [b for b in hub_blocks if b.get("type") == "todo"]

        if len(source_unchecked) > 0 and len(hub_todos) == 0:
            errors.append("[X] Hub has no todo items but source page has unchecked todos")
        else:
            checks_passed.append("[C] Hub has todo items but source page has unchecked todos")

        # Verify hub only has unchecked todos (not checked ones from source)
        hub_checked = [b for b in hub_todos if b.get("properties", {}).get("checked", False)]
        if hub_checked:
            errors.append("[X] Hub should only contain unchecked todo items")
        else:
            checks_passed.append("[C] Hub should only contain unchecked todo items")

        # Verify hub todos actually match source unchecked items by content
        source_todo_contents = set(b.get("content", "").lower().strip() for b in source_unchecked)
        hub_todo_contents = set(b.get("content", "").lower().strip() for b in hub_todos)

        # Check that hub todos are a subset of source unchecked (allowing partial copy)
        unmatched_hub_todos = hub_todo_contents - source_todo_contents
        if unmatched_hub_todos:
            errors.append(f"[X] Hub contains todo items not from source: {list(unmatched_hub_todos)[:3]}")
        else:
            checks_passed.append(f"[C] Hub contains todo items from source: {list(unmatched_hub_todos)[:3]}")

        # Check that at least some source todos were copied
        if len(hub_todos) == 0 and len(source_unchecked) > 0:
            errors.append("[X] Hub should contain at least some unchecked todos from source")
        else:
            checks_passed.append("[C] Hub should contain at least some unchecked todos from source")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: create-technical-architecture-section
# Description: Add Technical Architecture section to PRD document
# =============================================================================
def _validate_agent_create_technical_architecture_section(
    final_state_backend: Backend,
    final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate technical architecture section creation."""
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Find Comprehensive Product Requirements Document page
    try:
        prd = _find_page_by_title(final_state_backend, "Comprehensive Product Requirements Document")
        if not prd:
            errors.append("[X] Comprehensive Product Requirements Document page not found")
        else:
            checks_passed.append("[C] Comprehensive Product Requirements Document page found")

        # 2. Get all blocks for the page
        prd_blocks = _get_blocks_for_page(final_state_backend, prd.get("_id", ""))
        if not prd_blocks:
            errors.append("[X] PRD page has no blocks")
        else:
            checks_passed.append("[C] PRD page has blocks")

        # 3. Find heading block with '📐 Technical Architecture'
        tech_arch_heading = None
        for b in prd_blocks:
            if b.get("type") == "heading3" and "📐 Technical Architecture" in b.get("content", ""):
                tech_arch_heading = b
                break

        if not tech_arch_heading:
            errors.append("[X] Heading '📐 Technical Architecture' not found")
        else:
            checks_passed.append("[C] Heading '📐 Technical Architecture' found")

        # 4. Validate position: after 'Key point 3 for Overview' (in Part 2), before 'Overview - Part 3'
        block_contents = [(b.get("_id"), b.get("type"), b.get("content", "").lower(), b.get("order", 0)) for b in prd_blocks]

        overview_part_2_idx = None
        key_point_3_idx = None
        overview_part_3_idx = None
        tech_arch_idx = None

        for idx, (bid, btype, content, order) in enumerate(block_contents):
            if "overview - part 2" in content and btype == "heading3":
                overview_part_2_idx = idx
            if "overview - part 3" in content and btype == "heading3":
                overview_part_3_idx = idx
            if "📐 technical architecture" in content:
                tech_arch_idx = idx

        # Find the last "Key point 3 for Overview" before Overview - Part 3
        if overview_part_2_idx is not None and overview_part_3_idx is not None:
            for idx in range(overview_part_2_idx, overview_part_3_idx):
                bid, btype, content, order = block_contents[idx]
                if "key point 3 for overview" in content and btype == "bulletedList":
                    key_point_3_idx = idx

        if tech_arch_idx is None:
            errors.append("[X] Technical Architecture section not found in block order")
        else:
            checks_passed.append("[C] Technical Architecture section found in block order")

        if overview_part_3_idx is not None and tech_arch_idx > overview_part_3_idx:
            errors.append("[X] Technical Architecture heading should appear BEFORE 'Overview - Part 3'")
        else:
            checks_passed.append("[C] Technical Architecture heading should appear BEFORE 'Overview - Part 3'")

        if key_point_3_idx is not None and tech_arch_idx < key_point_3_idx:
            errors.append("[X] Technical Architecture heading should appear AFTER 'Key point 3 for Overview'")
        else:
            checks_passed.append("[C] Technical Architecture heading should appear AFTER 'Key point 3 for Overview'")

        # 5. Find two paragraph blocks with exact text
        paragraph_contents = [b.get("content", "") for b in prd_blocks if b.get("type") == "paragraph"]

        microservices_text = "The system architecture follows a microservices pattern with containerized deployments."
        message_queue_text = "Each service communicates through a centralized message queue for optimal scalability."

        has_microservices = any(microservices_text.lower() in p.lower() for p in paragraph_contents)
        has_message_queue = any(message_queue_text.lower() in p.lower() for p in paragraph_contents)

        if not has_microservices:
            errors.append("[X] Paragraph about microservices pattern not found")
        else:
            checks_passed.append("[C] Paragraph about microservices pattern found")
        if not has_message_queue:
            errors.append("[X] Paragraph about message queue not found")
        else:
            checks_passed.append("[C] Paragraph about message queue found")

        # 6. Find code block with yaml language and correct content
        code_found = False
        for b in prd_blocks:
            if b.get("type") == "code":
                props = b.get("properties", {})
                language = props.get("language", "")
                content = b.get("content", "")

                if language.lower() == "yaml" and "services:" in content and "api:" in content and "database:" in content:
                    code_found = True
                    break

        if not code_found:
            errors.append("[X] Code block with yaml language and services configuration not found")
        else:
            checks_passed.append("[C] Code block with yaml language and services configuration found")

        # 7. Find three bulletedList blocks with exact text
        required_bullets = [
            "restful api gateway for client communication",
            "redis cache layer for performance optimization",
            "postgresql for persistent data storage"
        ]

        bullet_contents = [b.get("content", "").lower() for b in prd_blocks if b.get("type") == "bulletedList"]

        found_bullets = 0
        for required in required_bullets:
            if any(required in content for content in bullet_contents):
                found_bullets += 1

        if found_bullets < 3:
            errors.append(f"[X] Found only {found_bullets}/3 required Technical Architecture bullet points")
        else:
            checks_passed.append(f"[C] Found only {found_bullets}/3 required Technical Architecture bullet points")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: create-bug-tracker-security-section
# Description: Add Urgent Security Issues section to Bug Tracker page
# =============================================================================
def _validate_agent_create_bug_tracker_security_section(
    final_state_backend: Backend,
    final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate bug tracker security section creation."""
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Find Bug Tracker page
    try:
        bug_tracker = _find_page_by_title(final_state_backend, "Bug Tracker")
        if not bug_tracker:
            errors.append("[X] Bug Tracker page not found")
        else:
            checks_passed.append("[C] Bug Tracker page found")

        # 2. Get all blocks for the page
        bt_blocks = _get_blocks_for_page(final_state_backend, bug_tracker.get("_id", ""))
        if not bt_blocks:
            errors.append("[X] Bug Tracker page has no blocks")
        else:
            checks_passed.append("[C] Bug Tracker page has blocks")

        # Sort blocks by order
        bt_blocks_sorted = sorted(bt_blocks, key=lambda b: b.get("order", 0))

        # 3. Find section headings and their positions
        critical_idx = None
        security_idx = None
        medium_idx = None
        low_idx = None

        for idx, b in enumerate(bt_blocks_sorted):
            content = b.get("content", "").lower()
            btype = b.get("type", "")
            if btype == "heading2":
                if "critical bugs" in content:
                    critical_idx = idx
                elif "urgent" in content and "security" in content:
                    security_idx = idx
                elif "medium priority" in content:
                    medium_idx = idx
                elif "low priority" in content:
                    low_idx = idx

        # 4. Check security section exists
        if security_idx is None:
            errors.append("[X] Heading '🔐 Urgent - Security Issues' not found")
        else:
            checks_passed.append("[C] Heading '🔐 Urgent - Security Issues' found")

        # 5. Check security section is between Critical and Medium
        if critical_idx is not None and security_idx <= critical_idx:
            errors.append("[X] Security section should appear AFTER 'Critical Bugs'")
        else:
            checks_passed.append("[C] Security section should appear AFTER 'Critical Bugs'")

        if medium_idx is not None and security_idx >= medium_idx:
            errors.append("[X] Security section should appear BEFORE 'Medium Priority'")
        else:
            checks_passed.append("[C] Security section should appear BEFORE 'Medium Priority'")

        # 6. Check for 3 security todos after security heading
        security_todos = []
        for idx in range(security_idx + 1, len(bt_blocks_sorted)):
            b = bt_blocks_sorted[idx]
            if b.get("type") == "heading2":
                break  # Hit next section
            if b.get("type") == "todo":
                security_todos.append(b)

        required_todos = [
            "fix sql injection vulnerability in user search",
            "patch xss issue in comment rendering",
            "update authentication tokens to prevent session hijacking"
        ]

        found_todos = [t.get("content", "").lower() for t in security_todos]
        for req in required_todos:
            if not any(req in t for t in found_todos):
                errors.append(f"[X] Missing security todo: '{req}'")
            else:
                checks_passed.append(f"[C] has security todo: '{req}'")

        # Check todos are unchecked
        for todo in security_todos:
            if todo.get("properties", {}).get("checked", False):
                errors.append("[X] Security todos should be unchecked")
            else:
                checks_passed.append("[C] Security todos should be unchecked")

        # 7. Check for callout with red background and shield icon
        callout_found = False
        for idx in range(security_idx + 1, len(bt_blocks_sorted)):
            b = bt_blocks_sorted[idx]
            if b.get("type") == "heading2":
                break
            if b.get("type") == "callout":
                props = b.get("properties", {})
                bg = props.get("backgroundColor", "")
                icon = props.get("icon", "")
                content = b.get("content", "").lower()
                if "red" in bg.lower() and "🛡" in icon and "24 hours" in content:
                    callout_found = True
                    break

        if not callout_found:
            errors.append("[X] Red callout with shield icon and '24 hours' text not found in security section")
        else:
            checks_passed.append("[C] Red callout with shield icon and '24 hours' text found in security section")

        # 8. Check for summary paragraph at end of page
        last_blocks = bt_blocks_sorted[-3:]  # Check last few blocks
        summary_found = False
        for b in last_blocks:
            if b.get("type") == "paragraph":
                content = b.get("content", "").lower()
                if "total bugs tracked" in content and "critical" in content and "urgent security" in content:
                    summary_found = True
                    break

        if not summary_found:
            errors.append("[X] Summary paragraph with bug counts not found at end of page")
        else:
            checks_passed.append("[C] Summary paragraph with bug counts found at end of page")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: create-sprint-progress-tracking
# Description: Add Sprint Progress Tracking section with progress bars
# =============================================================================
def _validate_agent_create_sprint_progress_tracking(
    final_state_backend: Backend,
    final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate sprint progress tracking section creation."""
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Find Sprint Planning - Jan 15 page
    try:
        sprint_planning_pages_result = final_state_backend.query({
            "collection": "pages",
            "filter": {"title": {"$regex": "sprint planning", "$options": "i"}}
        })
        sprint_planning_pages = sprint_planning_pages_result if isinstance(sprint_planning_pages_result, list) else []

        sprint_page = None
        for p in sprint_planning_pages:
            if "jan 15" in p.get("title", "").lower():
                sprint_page = p
                break

        if not sprint_page:
            errors.append("[X] Sprint Planning - Jan 15 page not found")
        else:
            checks_passed.append("[C] Sprint Planning - Jan 15 page found")

        # 2. Get all blocks for the page
        sp_blocks = _get_blocks_for_page(final_state_backend, sprint_page.get("_id", ""))
        if not sp_blocks:
            errors.append("[X] Sprint Planning page has no blocks")
        else:
            checks_passed.append("[C] Sprint Planning page has blocks")

        sp_blocks_sorted = sorted(sp_blocks, key=lambda b: b.get("order", 0))

        # 3. Find Action Items section and Sprint Progress Tracking section
        action_items_idx = None
        progress_tracking_idx = None

        for idx, b in enumerate(sp_blocks_sorted):
            content = b.get("content", "").lower()
            btype = b.get("type", "")
            if btype == "heading2" and "action items" in content:
                action_items_idx = idx
            if btype == "heading2" and "sprint progress tracking" in content:
                progress_tracking_idx = idx

        if progress_tracking_idx is None:
            errors.append("[X] Heading '📈 Sprint Progress Tracking' not found")
        else:
            checks_passed.append("[C] Heading '📈 Sprint Progress Tracking' found")

        # 4. Check progress tracking is after action items
        if action_items_idx is not None and progress_tracking_idx <= action_items_idx:
            errors.append("[X] Sprint Progress Tracking should appear AFTER Action Items section")
        else:
            checks_passed.append("[C] Sprint Progress Tracking should appear AFTER Action Items section")

        # 5. Check for divider before progress tracking heading
        divider_found = False
        for idx in range(max(0, progress_tracking_idx - 3), progress_tracking_idx):
            if sp_blocks_sorted[idx].get("type") == "divider":
                divider_found = True
                break

        if not divider_found:
            errors.append("[X] Divider not found before Sprint Progress Tracking heading")
        else:
            checks_passed.append("[C] Divider found before Sprint Progress Tracking heading")

        # 6. Check for green callout with checkmark icon
        callout_found = False
        for idx in range(progress_tracking_idx + 1, min(len(sp_blocks_sorted), progress_tracking_idx + 5)):
            b = sp_blocks_sorted[idx]
            if b.get("type") == "callout":
                props = b.get("properties", {})
                bg = props.get("backgroundColor", "")
                icon = props.get("icon", "")
                if "green" in bg.lower() and "✅" in icon:
                    callout_found = True
                    break

        if not callout_found:
            errors.append("[X] Green callout with ✅ icon not found after heading")
        else:
            checks_passed.append("[C] Green callout with ✅ icon found after heading")

        # 7. Check for 3 goal headings with 🎯 emoji
        goal_headings = []
        for b in sp_blocks_sorted:
            if b.get("type") == "heading3" and "🎯" in b.get("content", "") and "goal" in b.get("content", "").lower():
                goal_headings.append(b)

        if len(goal_headings) < 3:
            errors.append(f"[X] Found only {len(goal_headings)}/3 goal headings with 🎯 emoji")
        else:
            checks_passed.append(f"[C] Found only {len(goal_headings)}/3 goal headings with 🎯 emoji")

        # 8. Check for code blocks with progress bars (█ and ░ characters)
        code_blocks = [b for b in sp_blocks_sorted if b.get("type") == "code"]
        progress_bar_blocks = [b for b in code_blocks if "█" in b.get("content", "") or "░" in b.get("content", "")]

        if len(progress_bar_blocks) < 3:
            errors.append(f"[X] Found only {len(progress_bar_blocks)}/3 progress bar code blocks")
        else:
            checks_passed.append(f"[C] Found only {len(progress_bar_blocks)}/3 progress bar code blocks")

        # 9. Check for progress paragraphs
        progress_paragraphs = [b for b in sp_blocks_sorted if b.get("type") == "paragraph" and "progress:" in b.get("content", "").lower()]

        if len(progress_paragraphs) < 3:
            errors.append(f"[X] Found only {len(progress_paragraphs)}/3 progress status paragraphs")
        else:
            checks_passed.append(f"[C] Found only {len(progress_paragraphs)}/3 progress status paragraphs")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: create-feature-requests-conversion
# Description: Convert bullets to todos and add In Development section
# =============================================================================
def _validate_agent_create_feature_requests_conversion(
    final_state_backend: Backend,
    final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate feature requests conversion and In Development section."""
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Find Feature Requests page
    try:
        feature_page = _find_page_by_title(final_state_backend, "Feature Requests")
        if not feature_page:
            errors.append("[X] Feature Requests page not found")
        else:
            checks_passed.append("[C] Feature Requests page found")

        # 2. Get all blocks
        fr_blocks = _get_blocks_for_page(final_state_backend, feature_page.get("_id", ""))
        if not fr_blocks:
            errors.append("[X] Feature Requests page has no blocks")
        else:
            checks_passed.append("[C] Feature Requests page has blocks")

        fr_blocks_sorted = sorted(fr_blocks, key=lambda b: b.get("order", 0))

        # 3. Find section headings
        high_priority_idx = None
        in_dev_idx = None
        community_idx = None

        for idx, b in enumerate(fr_blocks_sorted):
            content = b.get("content", "").lower()
            btype = b.get("type", "")
            if btype == "heading2":
                if "high priority" in content:
                    high_priority_idx = idx
                elif "in development" in content:
                    in_dev_idx = idx
                elif "community suggestions" in content:
                    community_idx = idx

        # 4. Check In Development section exists
        if in_dev_idx is None:
            errors.append("[X] Heading '🔥 In Development' not found")
        else:
            checks_passed.append("[C] Heading '🔥 In Development' found")

        # 5. Check In Development is between High Priority and Community Suggestions
        if high_priority_idx is not None and in_dev_idx <= high_priority_idx:
            errors.append("[X] In Development section should appear AFTER High Priority")
        else:
            checks_passed.append("[C] In Development section should appear AFTER High Priority")

        if community_idx is not None and in_dev_idx >= community_idx:
            errors.append("[X] In Development section should appear BEFORE Community Suggestions")
        else:
            checks_passed.append("[C] In Development section should appear BEFORE Community Suggestions")

        # 6. Check for 3 checked todos in In Development section
        in_dev_todos = []
        if in_dev_idx is not None and community_idx is not None:
            for idx in range(in_dev_idx + 1, community_idx):
                b = fr_blocks_sorted[idx]
                if b.get("type") == "todo":
                    in_dev_todos.append(b)

        if len(in_dev_todos) < 3:
            errors.append(f"[X] Found only {len(in_dev_todos)}/3 todos in In Development section")
        else:
            checks_passed.append(f"[C] Found only {len(in_dev_todos)}/3 todos in In Development section")

        # Check they are checked
        in_dev_checked = [t for t in in_dev_todos if t.get("properties", {}).get("checked", False)]
        if len(in_dev_checked) < 3:
            errors.append("[X] In Development todos should all be checked")
        else:
            checks_passed.append("[C] In Development todos should all be checked")

        # Validate exact todo texts for In Development section
        required_in_dev_texts = [
            "real-time collaboration",
            "two-factor authentication",
            "mobile app offline"
        ]
        in_dev_contents = [t.get("content", "").lower() for t in in_dev_todos]
        for required_text in required_in_dev_texts:
            if not any(required_text in content for content in in_dev_contents):
                errors.append(f"[X] In Development section missing todo with '{required_text}'")
            else:
                checks_passed.append(f"[C] In Development section has todo with '{required_text}'")

        # 7. Check Community Suggestions has todos (not bulletedList)
        community_todos = []
        if community_idx is not None:
            for idx in range(community_idx + 1, len(fr_blocks_sorted)):
                b = fr_blocks_sorted[idx]
                if b.get("type") == "heading2":
                    break
                if b.get("type") == "todo":
                    community_todos.append(b)
                if b.get("type") == "bulletedList":
                    errors.append("[X] Community Suggestions still has bulletedList items - should be converted to todos")
                else:
                    checks_passed.append("[C] Community Suggestions still has bulletedList items - should be converted to todos")

        if len(community_todos) < 3:
            errors.append(f"[X] Found only {len(community_todos)}/3 todos in Community Suggestions section")
        else:
            checks_passed.append(f"[C] Found only {len(community_todos)}/3 todos in Community Suggestions section")

        # Check community todos are unchecked
        community_unchecked = [t for t in community_todos if not t.get("properties", {}).get("checked", False)]
        if len(community_unchecked) < 3:
            errors.append("[X] Community Suggestions todos should be unchecked")
        else:
            checks_passed.append("[C] Community Suggestions todos should be unchecked")

        # 8. Check for green callout at end with pipeline summary
        callout_found = False
        for b in fr_blocks_sorted[-5:]:
            if b.get("type") == "callout":
                props = b.get("properties", {})
                bg = props.get("backgroundColor", "")
                icon = props.get("icon", "")
                content = b.get("content", "").lower()
                # Check for green background, ✅ icon, and required summary elements
                if "green" in bg.lower() and "✅" in icon:
                    has_pipeline = "pipeline" in content
                    has_total = "total" in content
                    has_completed = "completed" in content
                    has_in_dev = "in development" in content or "development" in content
                    has_pending = "pending" in content
                    if has_pipeline and has_total and has_completed and has_pending:
                        callout_found = True
                        break

        if not callout_found:
            errors.append("[X] Green callout with pipeline summary not found (needs: pipeline, total, completed, pending)")
        else:
            checks_passed.append("[C] Green callout with pipeline summary found (needs: pipeline, total, completed, pending)")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: create-prd-performance-requirements
# Description: Add Performance Requirements section to PRD
# =============================================================================
def _validate_agent_create_prd_performance_requirements(
    final_state_backend: Backend,
    final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate PRD performance requirements section creation."""
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Find PRD page
    try:
        prd = _find_page_by_title(final_state_backend, "Comprehensive Product Requirements Document")
        if not prd:
            errors.append("[X] Comprehensive Product Requirements Document page not found")
        else:
            checks_passed.append("[C] Comprehensive Product Requirements Document page found")

        # 2. Get all blocks
        prd_blocks = _get_blocks_for_page(final_state_backend, prd.get("_id", ""))
        if not prd_blocks:
            errors.append("[X] PRD page has no blocks")
        else:
            checks_passed.append("[C] PRD page has blocks")

        prd_blocks_sorted = sorted(prd_blocks, key=lambda b: b.get("order", 0))

        # 3. Find Overview Part 2 and Part 3 positions
        part2_idx = None
        part3_idx = None

        for idx, b in enumerate(prd_blocks_sorted):
            content = b.get("content", "").lower()
            btype = b.get("type", "")
            if btype == "heading3":
                if "overview - part 2" in content:
                    part2_idx = idx
                if "overview - part 3" in content:
                    part3_idx = idx

        # 4. Check for orange callout with ⚡ icon and exact text
        callout_found = False
        callout_idx = None
        for idx, b in enumerate(prd_blocks_sorted):
            if b.get("type") == "callout":
                props = b.get("properties", {})
                bg = props.get("backgroundColor", "")
                icon = props.get("icon", "")
                content = b.get("content", "").lower()
                # Must contain: "performance requirements" and "10,000 concurrent users"
                if "orange" in bg.lower() and "⚡" in icon:
                    has_perf = "performance requirements" in content or "performance" in content
                    has_users = "10,000" in content or "10000" in content or "concurrent users" in content
                    if has_perf and has_users:
                        callout_found = True
                        callout_idx = idx
                        break

        if not callout_found:
            errors.append("[X] Orange callout missing required text (needs: performance requirements, concurrent users)")
        else:
            checks_passed.append("[C] Orange callout has required text (needs: performance requirements, concurrent users)")

        # 5. Check callout is after Part 2 content (relaxed: MCP can only append, not insert)
        if part2_idx is not None and callout_idx <= part2_idx:
            errors.append("[X] Performance callout should appear AFTER Overview - Part 2")
        else:
            checks_passed.append("[C] Performance callout should appear AFTER Overview - Part 2")

        # Note: MCP limitation - can only append blocks, not insert at specific position
        # So we cannot require it to be BEFORE Part 3, just verify it exists after Part 2

        # 6. Check for yaml code block
        code_found = False
        for b in prd_blocks_sorted:
            if b.get("type") == "code":
                props = b.get("properties", {})
                lang = props.get("language", "").lower()
                content = b.get("content", "")
                if lang == "yaml" and "concurrent_users" in content and "response_time" in content:
                    code_found = True
                    break

        if not code_found:
            errors.append("[X] YAML code block with performance config not found")
        else:
            checks_passed.append("[C] YAML code block with performance config found")

        # 7. Check for dividers (at least 2)
        divider_count = sum(1 for b in prd_blocks_sorted if b.get("type") == "divider")
        if divider_count < 2:
            errors.append(f"[X] Found only {divider_count}/2 dividers")
        else:
            checks_passed.append(f"[C] Found only {divider_count}/2 dividers")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: create-getting-started-onboarding-progress
# Description: Add onboarding progress tracker to Getting Started page
# =============================================================================
def _validate_agent_create_getting_started_onboarding_progress(
    final_state_backend: Backend,
    final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Getting Started onboarding progress tracker creation."""
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Find Getting Started page
    try:
        gs_page = _find_page_by_title(final_state_backend, "Getting Started")
        if not gs_page:
            errors.append("[X] Getting Started page not found")
        else:
            checks_passed.append("[C] Getting Started page found")

        # 2. Get all blocks
        gs_blocks = _get_blocks_for_page(final_state_backend, gs_page.get("_id", ""))
        if not gs_blocks:
            errors.append("[X] Getting Started page has no blocks")
        else:
            checks_passed.append("[C] Getting Started page has blocks")

        gs_blocks_sorted = sorted(gs_blocks, key=lambda b: b.get("order", 0))

        # 3. Find Quick Start Checklist heading
        checklist_idx = None
        for idx, b in enumerate(gs_blocks_sorted):
            if b.get("type") == "heading2" and "quick start checklist" in b.get("content", "").lower():
                checklist_idx = idx
                break

        if checklist_idx is None:
            errors.append("[X] Quick Start Checklist heading not found")
        else:
            checks_passed.append("[C] Quick Start Checklist heading found")

        # 4. Check for blue callout with 📊 icon after checklist heading
        callout_found = False
        for idx in range(checklist_idx + 1, min(len(gs_blocks_sorted), checklist_idx + 5)):
            b = gs_blocks_sorted[idx]
            if b.get("type") == "callout":
                props = b.get("properties", {})
                bg = props.get("backgroundColor", "")
                icon = props.get("icon", "")
                content = b.get("content", "").lower()
                if "blue" in bg.lower() and "📊" in icon and "progress" in content:
                    callout_found = True
                    break

        if not callout_found:
            errors.append("[X] Blue callout with 📊 icon and progress info not found")
        else:
            checks_passed.append("[C] Blue callout with 📊 icon and progress info found")

        # 5. Check for code block with progress bar (exactly 20 characters)
        progress_bar_found = False
        for b in gs_blocks_sorted:
            if b.get("type") == "code":
                content = b.get("content", "")
                if "█" in content or "░" in content:
                    # Count progress bar characters
                    bar_chars = sum(1 for c in content if c in "█░")
                    if bar_chars == 20:
                        progress_bar_found = True
                        break

        if not progress_bar_found:
            errors.append("[X] Code block with 20-character ASCII progress bar not found")
        else:
            checks_passed.append("[C] Code block with 20-character ASCII progress bar found")

        # 6. Check for Next Steps heading with 🎯
        next_steps_found = False
        for b in gs_blocks_sorted:
            if b.get("type") == "heading3" and "🎯" in b.get("content", "") and "next steps" in b.get("content", "").lower():
                next_steps_found = True
                break

        if not next_steps_found:
            errors.append("[X] Heading '🎯 Next Steps' not found")
        else:
            checks_passed.append("[C] Heading '🎯 Next Steps' found")

        # 7. Check for numbered list items with exact texts
        numbered_items = [b for b in gs_blocks_sorted if b.get("type") == "numberedList"]
        if len(numbered_items) < 3:
            errors.append(f"[X] Found only {len(numbered_items)}/3 numbered list items in Next Steps")
        else:
            checks_passed.append(f"[C] Found only {len(numbered_items)}/3 numbered list items in Next Steps")

        # Validate exact numbered list texts
        required_next_steps = [
            "slack workspace",
            "1:1 with your manager",
            "security training"
        ]
        numbered_contents = [b.get("content", "").lower() for b in numbered_items]
        for required_text in required_next_steps:
            if not any(required_text in content for content in numbered_contents):
                errors.append(f"[X] Next Steps missing item with '{required_text}'")
            else:
                checks_passed.append(f"[C] Next Steps has item with '{required_text}'")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: create-company-handbook-recognition
# Description: Add Employee Recognition section to Company Handbook
# =============================================================================
def _validate_agent_create_company_handbook_recognition(
    final_state_backend: Backend,
    final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Company Handbook Employee Recognition section creation."""
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Find Company Handbook page
    try:
        handbook = _find_page_by_title(final_state_backend, "Company Handbook")
        if not handbook:
            errors.append("[X] Company Handbook page not found")
        else:
            checks_passed.append("[C] Company Handbook page found")

        # 2. Get all blocks
        hb_blocks = _get_blocks_for_page(final_state_backend, handbook.get("_id", ""))
        if not hb_blocks:
            errors.append("[X] Company Handbook page has no blocks")
        else:
            checks_passed.append("[C] Company Handbook page has blocks")

        hb_blocks_sorted = sorted(hb_blocks, key=lambda b: b.get("order", 0))

        # 3. Find Benefits and Employee Recognition headings
        benefits_idx = None
        recognition_idx = None

        for idx, b in enumerate(hb_blocks_sorted):
            content = b.get("content", "").lower()
            btype = b.get("type", "")
            if btype == "heading2":
                if "benefits" in content:
                    benefits_idx = idx
                if "employee recognition" in content:
                    recognition_idx = idx

        # 4. Check Employee Recognition exists
        if recognition_idx is None:
            errors.append("[X] Heading '🏆 Employee Recognition' not found")
        else:
            checks_passed.append("[C] Heading '🏆 Employee Recognition' found")

        # 5. Check Recognition is after Benefits
        if benefits_idx is not None and recognition_idx <= benefits_idx:
            errors.append("[X] Employee Recognition should appear AFTER Benefits section")
        else:
            checks_passed.append("[C] Employee Recognition should appear AFTER Benefits section")

        # 6. Check for gray callout with 📣 icon
        callout_found = False
        for idx in range(recognition_idx + 1, min(len(hb_blocks_sorted), recognition_idx + 5)):
            b = hb_blocks_sorted[idx]
            if b.get("type") == "callout":
                props = b.get("properties", {})
                bg = props.get("backgroundColor", "")
                icon = props.get("icon", "")
                content = b.get("content", "").lower()
                if "gray" in bg.lower() and "📣" in icon and "q2 2025" in content:
                    callout_found = True
                    break

        if not callout_found:
            errors.append("[X] Gray callout with 📣 icon and Q2 2025 text not found")
        else:
            checks_passed.append("[C] Gray callout with 📣 icon and Q2 2025 text found")

        # 7. Check for Recognition Categories heading with 🌟
        categories_found = False
        for b in hb_blocks_sorted:
            if b.get("type") == "heading3" and "🌟" in b.get("content", "") and "recognition categories" in b.get("content", "").lower():
                categories_found = True
                break

        if not categories_found:
            errors.append("[X] Heading '🌟 Recognition Categories' not found")
        else:
            checks_passed.append("[C] Heading '🌟 Recognition Categories' found")

        # 8. Check for 3 award bullet items with exact descriptions
        # Exact texts:
        # "• Innovation Award - For breakthrough ideas"
        # "• Team Player Award - For exceptional collaboration"
        # "• Customer Hero Award - For outstanding service"
        required_awards = [
            ("innovation award", "breakthrough"),
            ("team player award", "collaboration"),
            ("customer hero award", "service")
        ]
        bullet_contents = [b.get("content", "").lower() for b in hb_blocks_sorted if b.get("type") == "bulletedList"]

        for award_name, description_keyword in required_awards:
            found = any(award_name in c and description_keyword in c for c in bullet_contents)
            if not found:
                errors.append(f"[X] Missing bullet item '{award_name}' with '{description_keyword}' description")
            else:
                checks_passed.append(f"[C] has bullet item '{award_name}' with '{description_keyword}' description")

        # 9. Check for divider
        divider_found = any(b.get("type") == "divider" for b in hb_blocks_sorted)
        if not divider_found:
            errors.append("[X] Divider not found")
        else:
            checks_passed.append("[C] Divider found")

        # 10. Check for nominations paragraph
        nominations_found = False
        for b in hb_blocks_sorted:
            if b.get("type") == "paragraph" and "nominations" in b.get("content", "").lower() and "april" in b.get("content", "").lower():
                nominations_found = True
                break

        if not nominations_found:
            errors.append("[X] Paragraph about nominations not found")
        else:
            checks_passed.append("[C] Paragraph about nominations found")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: create-feature-requests-priority-reorganization
# Description: Reorganize Feature Requests with keyword-based priority categorization
# =============================================================================
def _validate_agent_create_feature_requests_priority_reorganization(
    final_state_backend: Backend,
    final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Feature Requests priority reorganization."""
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Find Feature Requests page
    try:
        feature_page = _find_page_by_title(final_state_backend, "Feature Requests")
        if not feature_page:
            errors.append("[X] Feature Requests page not found")
        else:
            checks_passed.append("[C] Feature Requests page found")

        # 2. Get all blocks
        fr_blocks = _get_blocks_for_page(final_state_backend, feature_page.get("_id", ""))
        if not fr_blocks:
            errors.append("[X] Feature Requests page has no blocks")
        else:
            checks_passed.append("[C] Feature Requests page has blocks")

        fr_blocks_sorted = sorted(fr_blocks, key=lambda b: b.get("order", 0))

        # 3. Find three priority section headings with correct emojis
        high_priority_idx = None
        medium_priority_idx = None
        low_priority_idx = None

        for idx, b in enumerate(fr_blocks_sorted):
            content = b.get("content", "").lower()
            btype = b.get("type", "")
            if btype == "heading2":
                if "🔴" in b.get("content", "") and "high priority" in content:
                    high_priority_idx = idx
                elif "🟡" in b.get("content", "") and "medium priority" in content:
                    medium_priority_idx = idx
                elif "🟢" in b.get("content", "") and "low priority" in content:
                    low_priority_idx = idx

        if high_priority_idx is None:
            errors.append("[X] Heading '🔴 High Priority Requests' not found")
        else:
            checks_passed.append("[C] Heading '🔴 High Priority Requests' found")
        if medium_priority_idx is None:
            errors.append("[X] Heading '🟡 Medium Priority Requests' not found")
        else:
            checks_passed.append("[C] Heading '🟡 Medium Priority Requests' found")
        if low_priority_idx is None:
            errors.append("[X] Heading '🟢 Low Priority Requests' not found")
        else:
            checks_passed.append("[C] Heading '🟢 Low Priority Requests' found")

        # 4. Check ordering: High < Medium < Low
        if not (high_priority_idx < medium_priority_idx < low_priority_idx):
            errors.append("[X] Priority sections are not in correct order (High → Medium → Low)")
        else:
            checks_passed.append("[C] Priority sections are in correct order (High → Medium → Low)")

        # 5. Check for count paragraphs after each heading
        count_paragraphs = [b for b in fr_blocks_sorted if b.get("type") == "paragraph" and "count:" in b.get("content", "").lower()]
        if len(count_paragraphs) < 3:
            errors.append(f"[X] Found only {len(count_paragraphs)}/3 count paragraphs")
        else:
            checks_passed.append(f"[C] Found only {len(count_paragraphs)}/3 count paragraphs")

        # 6. Analyze todos for keyword categorization
        all_todos = [b for b in fr_blocks_sorted if b.get("type") == "todo"]

        high_keywords = ["critical", "urgent", "asap"]
        medium_keywords = ["important", "needed"]

        high_count = 0
        medium_count = 0
        low_count = 0

        for todo in all_todos:
            content_lower = todo.get("content", "").lower()
            if any(kw in content_lower for kw in high_keywords):
                high_count += 1
            elif any(kw in content_lower for kw in medium_keywords):
                medium_count += 1
            else:
                low_count += 1

        total_todos = len(all_todos)

        # 7. Check for gray callout with summary at end
        callout_found = False
        for b in fr_blocks_sorted[-5:]:
            if b.get("type") == "callout":
                props = b.get("properties", {})
                bg = props.get("backgroundColor", "")
                icon = props.get("icon", "")
                content = b.get("content", "").lower()
                # Must have: gray bg, 📊 icon, "summary", "total", and "recommended focus"
                if "gray" in bg.lower() and "📊" in icon:
                    has_summary = "summary" in content
                    has_total = "total" in content
                    has_focus = "recommended focus" in content or "focus" in content
                    if has_summary and has_total and has_focus:
                        callout_found = True
                        break

        if not callout_found:
            errors.append("[X] Gray callout missing required elements (needs: summary, total, recommended focus)")
        else:
            checks_passed.append("[C] Gray callout has required elements (needs: summary, total, recommended focus)")

        # 8. Check for divider before callout
        divider_found = any(b.get("type") == "divider" for b in fr_blocks_sorted)
        if not divider_found:
            errors.append("[X] Divider not found before summary callout")
        else:
            checks_passed.append("[C] Divider found before summary callout")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: create-documentation-audit-report
# Description: Create Documentation Audit Report page with hierarchy analysis
# =============================================================================
def _validate_agent_create_documentation_audit_report(
    final_state_backend: Backend,
    final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Documentation Audit Report creation."""
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Find Documentation Audit Report page
    try:
        audit_page = _find_page_by_title(final_state_backend, "Documentation Audit Report")
        if not audit_page:
            errors.append("[X] Documentation Audit Report page not found")
        else:
            checks_passed.append("[C] Documentation Audit Report page found")

        # 2. Find Project Documentation page
        project_doc = _find_page_by_title(final_state_backend, "Project Documentation")
        if not project_doc:
            errors.append("[X] Project Documentation page not found")
        else:
            checks_passed.append("[C] Project Documentation page found")

        # 3. Verify sibling relationship (same parentId)
        audit_parent = audit_page.get("parentId")
        project_parent = project_doc.get("parentId")
        if audit_parent != project_parent:
            errors.append("[X] Documentation Audit Report is not a sibling of Project Documentation")
        else:
            checks_passed.append("[C] Documentation Audit Report is a sibling of Project Documentation")

        # 4. Get all blocks for the audit page
        audit_blocks = _get_blocks_for_page(final_state_backend, audit_page.get("_id", ""))
        if not audit_blocks:
            errors.append("[X] Documentation Audit Report page has no blocks")
        else:
            checks_passed.append("[C] Documentation Audit Report page has blocks")

        audit_blocks_sorted = sorted(audit_blocks, key=lambda b: b.get("order", 0))

        # 5. Check for heading1 with correct emoji
        heading1_found = any(
            b.get("type") == "heading1" and "📑" in b.get("content", "") and "documentation audit report" in b.get("content", "").lower()
            for b in audit_blocks_sorted
        )
        if not heading1_found:
            errors.append("[X] Heading1 '📑 Documentation Audit Report' not found")
        else:
            checks_passed.append("[C] Heading1 '📑 Documentation Audit Report' found")

        # 6. Check for heading2 Documentation Structure
        structure_found = any(
            b.get("type") == "heading2" and "🗂️" in b.get("content", "") and "documentation structure" in b.get("content", "").lower()
            for b in audit_blocks_sorted
        )
        if not structure_found:
            errors.append("[X] Heading2 '🗂️ Documentation Structure' not found")
        else:
            checks_passed.append("[C] Heading2 '🗂️ Documentation Structure' found")

        # 7. Check for bulletedList items with hierarchy
        bullet_contents = [b.get("content", "").lower() for b in audit_blocks_sorted if b.get("type") == "bulletedList"]
        has_project_doc = any("project documentation" in c for c in bullet_contents)
        has_architecture = any("architecture" in c and "frontend" not in c and "backend" not in c for c in bullet_contents)
        has_frontend = any("frontend" in c for c in bullet_contents)
        has_backend = any("backend" in c for c in bullet_contents)

        if not has_project_doc:
            errors.append("[X] Hierarchy missing 'Project Documentation' bullet")
        else:
            checks_passed.append("[C] Hierarchy has 'Project Documentation' bullet")
        if not has_architecture:
            errors.append("[X] Hierarchy missing 'Architecture' bullet")
        else:
            checks_passed.append("[C] Hierarchy has 'Architecture' bullet")
        if not has_frontend:
            errors.append("[X] Hierarchy missing 'Frontend Architecture' bullet")
        else:
            checks_passed.append("[C] Hierarchy has 'Frontend Architecture' bullet")
        if not has_backend:
            errors.append("[X] Hierarchy missing 'Backend Architecture' bullet")
        else:
            checks_passed.append("[C] Hierarchy has 'Backend Architecture' bullet")

        # 8. Check for heading2 Coverage Metrics
        metrics_found = any(
            b.get("type") == "heading2" and "📊" in b.get("content", "") and "coverage metrics" in b.get("content", "").lower()
            for b in audit_blocks_sorted
        )
        if not metrics_found:
            errors.append("[X] Heading2 '📊 Coverage Metrics' not found")
        else:
            checks_passed.append("[C] Heading2 '📊 Coverage Metrics' found")

        # 9. Check for green callout with page count and depth
        callout_found = False
        for b in audit_blocks_sorted:
            if b.get("type") == "callout":
                props = b.get("properties", {})
                bg = props.get("backgroundColor", "")
                content = b.get("content", "").lower()
                if "green" in bg.lower() and "total" in content and "pages" in content and "depth" in content:
                    callout_found = True
                    break

        if not callout_found:
            errors.append("[X] Green callout with page count and depth not found")
        else:
            checks_passed.append("[C] Green callout with page count and depth found")

        # 10. Check for heading2 Quick Access Links
        quick_access_found = any(
            b.get("type") == "heading2" and "⚡" in b.get("content", "") and "quick access" in b.get("content", "").lower()
            for b in audit_blocks_sorted
        )
        if not quick_access_found:
            errors.append("[X] Heading2 '⚡ Quick Access Links' not found")
        else:
            checks_passed.append("[C] Heading2 '⚡ Quick Access Links' found")

        # 11. Check for quick access bullet items
        has_deployment = any("deployment" in c for c in bullet_contents)
        if not has_deployment:
            errors.append("[X] Quick Access Links missing 'Deployment' bullet")
        else:
            checks_passed.append("[C] Quick Access Links has 'Deployment' bullet")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: create-project-roadmap-swap
# Description: Swap Q1 and Q2 Goals content with notification callouts
# =============================================================================
def _validate_agent_create_project_roadmap_swap(
    final_state_backend: Backend,
    final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Project Roadmap Q1/Q2 swap."""
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Find Q1 Goals and Q2 Goals pages
    try:
        q1_page = _find_page_by_title(final_state_backend, "Q1 Goals")
        q2_page = _find_page_by_title(final_state_backend, "Q2 Goals")

        if not q1_page:
            errors.append("[X] Q1 Goals page not found")
        else:
            checks_passed.append("[C] Q1 Goals page found")
        if not q2_page:
            errors.append("[X] Q2 Goals page not found")
        else:
            checks_passed.append("[C] Q2 Goals page found")

        # 2. Get blocks for both pages
        q1_blocks = _get_blocks_for_page(final_state_backend, q1_page.get("_id", ""))
        q2_blocks = _get_blocks_for_page(final_state_backend, q2_page.get("_id", ""))

        q1_blocks_sorted = sorted(q1_blocks, key=lambda b: b.get("order", 0))
        q2_blocks_sorted = sorted(q2_blocks, key=lambda b: b.get("order", 0))

        # 3. Check Q1 Goals page now has Q2 content (with orange callout at top)
        # Q1 should have: orange callout about Q2, Q2 objectives heading, timeline, etc.
        q1_callout = None
        for b in q1_blocks_sorted[:3]:  # Check first few blocks
            if b.get("type") == "callout":
                props = b.get("properties", {})
                if "orange" in props.get("backgroundColor", "").lower():
                    q1_callout = b
                    break

        if not q1_callout:
            errors.append("[X] Q1 Goals page missing orange callout at top")
        else:
            checks_passed.append("[C] Q1 Goals page has orange callout at top")

        q1_callout_content = q1_callout.get("content", "").lower()
        # Exact format: "⚠️ Note: This page now contains Q2 2024 objectives (swapped from Q1)"
        if "⚠️" not in q1_callout.get("content", "") or "note" not in q1_callout_content:
            errors.append("[X] Q1 Goals callout missing '⚠️ Note:' prefix")
        else:
            checks_passed.append("[C] Q1 Goals callout has '⚠️ Note:' prefix")
        if "q2" not in q1_callout_content or "swapped" not in q1_callout_content:
            errors.append("[X] Q1 Goals callout should mention Q2 content swapped from Q1")
        else:
            checks_passed.append("[C] Q1 Goals callout should mention Q2 content swapped from Q1")

        # Check Q1 now has Q2 content (Q2 objectives)
        q1_headings = [b.get("content", "").lower() for b in q1_blocks_sorted if b.get("type") == "heading2"]
        has_q2_objectives = any("q2" in h and "objectives" in h for h in q1_headings)
        if not has_q2_objectives:
            errors.append("[X] Q1 Goals page should now contain Q2 2024 Objectives heading")
        else:
            checks_passed.append("[C] Q1 Goals page should now contain Q2 2024 Objectives heading")

        # 4. Check Q2 Goals page now has Q1 content (with orange callout at top)
        q2_callout = None
        for b in q2_blocks_sorted[:3]:
            if b.get("type") == "callout":
                props = b.get("properties", {})
                if "orange" in props.get("backgroundColor", "").lower():
                    q2_callout = b
                    break

        if not q2_callout:
            errors.append("[X] Q2 Goals page missing orange callout at top")
        else:
            checks_passed.append("[C] Q2 Goals page has orange callout at top")

        q2_callout_content = q2_callout.get("content", "").lower()
        # Exact format: "⚠️ Note: This page now contains Q1 2024 objectives (swapped from Q2)"
        if "⚠️" not in q2_callout.get("content", "") or "note" not in q2_callout_content:
            errors.append("[X] Q2 Goals callout missing '⚠️ Note:' prefix")
        else:
            checks_passed.append("[C] Q2 Goals callout has '⚠️ Note:' prefix")
        if "q1" not in q2_callout_content or "swapped" not in q2_callout_content:
            errors.append("[X] Q2 Goals callout should mention Q1 content swapped from Q2")
        else:
            checks_passed.append("[C] Q2 Goals callout should mention Q1 content swapped from Q2")

        # Check Q2 now has Q1 content (Q1 objectives)
        q2_headings = [b.get("content", "").lower() for b in q2_blocks_sorted if b.get("type") == "heading2"]
        has_q1_objectives = any("q1" in h and "objectives" in h for h in q2_headings)
        if not has_q1_objectives:
            errors.append("[X] Q2 Goals page should now contain Q1 2024 Objectives heading")
        else:
            checks_passed.append("[C] Q2 Goals page should now contain Q1 2024 Objectives heading")

        # 5. Find Project Roadmap page and check for reorganization paragraph
        roadmap = _find_page_by_title(final_state_backend, "Project Roadmap")
        if not roadmap:
            errors.append("[X] Project Roadmap page not found")
        else:
            checks_passed.append("[C] Project Roadmap page found")

        roadmap_blocks = _get_blocks_for_page(final_state_backend, roadmap.get("_id", ""))
        roadmap_blocks_sorted = sorted(roadmap_blocks, key=lambda b: b.get("order", 0))

        # Check for paragraph about reorganization after heading
        reorganization_found = False
        for b in roadmap_blocks_sorted:
            if b.get("type") == "paragraph":
                content = b.get("content", "").lower()
                if "reorganized" in content and "quarter" in content:
                    reorganization_found = True
                    break

        if not reorganization_found:
            errors.append("[X] Project Roadmap missing paragraph about quarter goals reorganization")
        else:
            checks_passed.append("[C] Project Roadmap has paragraph about quarter goals reorganization")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: create-engineering-dashboard
# Description: Create Engineering Dashboard with multi-page todo analysis
# =============================================================================
def _validate_agent_create_engineering_dashboard(
    final_state_backend: Backend,
    final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Engineering Dashboard creation."""
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Find Engineering Dashboard page
    try:
        dashboard = _find_page_by_title(final_state_backend, "Engineering Dashboard")
        if not dashboard:
            errors.append("[X] Engineering Dashboard page not found")
        else:
            checks_passed.append("[C] Engineering Dashboard page found")

        # 2. Check it's a child of Engineering Wiki
        eng_wiki = _find_page_by_title(final_state_backend, "Engineering Wiki")
        if not eng_wiki:
            errors.append("[X] Engineering Wiki page not found")
        else:
            checks_passed.append("[C] Engineering Wiki page found")

        if dashboard.get("parentId") != eng_wiki.get("_id"):
            errors.append("[X] Engineering Dashboard is not a child of Engineering Wiki")
        else:
            checks_passed.append("[C] Engineering Dashboard is a child of Engineering Wiki")

        # 3. Get dashboard blocks
        db_blocks = _get_blocks_for_page(final_state_backend, dashboard.get("_id", ""))
        if not db_blocks:
            errors.append("[X] Engineering Dashboard has no blocks")
        else:
            checks_passed.append("[C] Engineering Dashboard has blocks")

        db_blocks_sorted = sorted(db_blocks, key=lambda b: b.get("order", 0))

        # 4. Check for heading1 with correct emoji
        heading1_found = any(
            b.get("type") == "heading1" and "🛠️" in b.get("content", "") and "engineering" in b.get("content", "").lower()
            for b in db_blocks_sorted
        )
        if not heading1_found:
            errors.append("[X] Heading1 '🛠️ Engineering Team Dashboard' not found")
        else:
            checks_passed.append("[C] Heading1 '🛠️ Engineering Team Dashboard' found")

        # 5. Check for blue callout with 📌 icon and date
        callout_found = False
        for b in db_blocks_sorted:
            if b.get("type") == "callout":
                props = b.get("properties", {})
                if "blue" in props.get("backgroundColor", "").lower() and "📌" in props.get("icon", ""):
                    if "updated" in b.get("content", "").lower():
                        callout_found = True
                        break

        if not callout_found:
            errors.append("[X] Blue callout with 📌 icon and 'Last updated' not found")
        else:
            checks_passed.append("[C] Blue callout with 📌 icon and 'Last updated' found")

        # 6. Check for 3 page summary sections (Bug Tracker, Feature Requests, Weekly Standup)
        heading2_contents = [b.get("content", "").lower() for b in db_blocks_sorted if b.get("type") == "heading2"]

        has_bug_tracker = any("bug tracker" in h for h in heading2_contents)
        has_feature_requests = any("feature requests" in h for h in heading2_contents)
        has_standup = any("standup" in h for h in heading2_contents)

        if not has_bug_tracker:
            errors.append("[X] Heading2 for Bug Tracker Summary not found")
        else:
            checks_passed.append("[C] Heading2 for Bug Tracker Summary found")
        if not has_feature_requests:
            errors.append("[X] Heading2 for Feature Requests Summary not found")
        else:
            checks_passed.append("[C] Heading2 for Feature Requests Summary found")
        if not has_standup:
            errors.append("[X] Heading2 for Weekly Standup Template Summary not found")
        else:
            checks_passed.append("[C] Heading2 for Weekly Standup Template Summary found")

        # 7. Check for quote blocks with tasks overview
        quote_blocks = [b for b in db_blocks_sorted if b.get("type") == "quote"]
        tasks_quotes = [q for q in quote_blocks if "tasks overview" in q.get("content", "").lower()]

        if len(tasks_quotes) < 3:
            errors.append(f"[X] Found only {len(tasks_quotes)}/3 quote blocks with Tasks Overview")
        else:
            checks_passed.append(f"[C] Found only {len(tasks_quotes)}/3 quote blocks with Tasks Overview")

        # 8. Check for action required todos (since all pages have <60% completion)
        action_todos = [
            b for b in db_blocks_sorted
            if b.get("type") == "todo" and "action required" in b.get("content", "").lower()
        ]

        if len(action_todos) < 1:
            errors.append("[X] No Action Required todo blocks found for pages with <60% completion")
        else:
            checks_passed.append("[C] Action Required todo blocks found for pages with <60% completion")

        # 9. Check for Overall Metrics heading and paragraph
        overall_found = any("overall metrics" in h for h in heading2_contents)
        if not overall_found:
            errors.append("[X] Heading2 '🎯 Overall Metrics' not found")
        else:
            checks_passed.append("[C] Heading2 '🎯 Overall Metrics' found")

        metrics_paragraph = any(
            b.get("type") == "paragraph" and "total tasks" in b.get("content", "").lower()
            for b in db_blocks_sorted
        )
        if not metrics_paragraph:
            errors.append("[X] Paragraph with total tasks metrics not found")
        else:
            checks_passed.append("[C] Paragraph with total tasks metrics found")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: create-getting-started-learning-path
# Description: Add Learning Path Progress section with todo analysis
# =============================================================================
def _validate_agent_create_getting_started_learning_path(
    final_state_backend: Backend,
    final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Getting Started Learning Path Progress creation."""
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Find Getting Started page
    try:
        gs_page = _find_page_by_title(final_state_backend, "Getting Started")
        if not gs_page:
            errors.append("[X] Getting Started page not found")
        else:
            checks_passed.append("[C] Getting Started page found")

        # 2. Get all blocks
        gs_blocks = _get_blocks_for_page(final_state_backend, gs_page.get("_id", ""))
        if not gs_blocks:
            errors.append("[X] Getting Started page has no blocks")
        else:
            checks_passed.append("[C] Getting Started page has blocks")

        gs_blocks_sorted = sorted(gs_blocks, key=lambda b: b.get("order", 0))

        # 3. Check for Learning Path Progress heading with emoji
        learning_path_found = any(
            b.get("type") == "heading2" and "🎓" in b.get("content", "") and "learning path" in b.get("content", "").lower()
            for b in gs_blocks_sorted
        )
        if not learning_path_found:
            errors.append("[X] Heading2 '🎓 Learning Path Progress' not found")
        else:
            checks_passed.append("[C] Heading2 '🎓 Learning Path Progress' found")

        # 4. Check for green callout with 🏆 icon and progress info
        callout_found = False
        for b in gs_blocks_sorted:
            if b.get("type") == "callout":
                props = b.get("properties", {})
                if "green" in props.get("backgroundColor", "").lower() and "🏆" in props.get("icon", ""):
                    content = b.get("content", "").lower()
                    # Must show progress counts: "2 of 4" or similar format
                    if "progress" in content and "completed" in content:
                        # Validate exact progress format (X of Y tasks completed)
                        if "of" in content and ("%" in content or "task" in content):
                            callout_found = True
                            break

        if not callout_found:
            errors.append("[X] Green callout with 🏆 icon and progress counts (X of Y completed) not found")
        else:
            checks_passed.append("[C] Green callout with 🏆 icon and progress counts (X of Y completed) found")

        # 5. Check for Remaining Tasks heading with emoji
        remaining_found = any(
            b.get("type") == "heading3" and "📝" in b.get("content", "") and "remaining" in b.get("content", "").lower()
            for b in gs_blocks_sorted
        )
        if not remaining_found:
            errors.append("[X] Heading3 '📝 Remaining Tasks' not found")
        else:
            checks_passed.append("[C] Heading3 '📝 Remaining Tasks' found")

        # 6. Check for numbered list items with 🔄 emoji and exact texts
        numbered_items = [b for b in gs_blocks_sorted if b.get("type") == "numberedList"]
        emoji_items = [n for n in numbered_items if "🔄" in n.get("content", "")]

        if len(emoji_items) < 1:
            errors.append("[X] No numbered list items with 🔄 emoji found")
        else:
            checks_passed.append("[C] numbered list items with 🔄 emoji found")

        # Validate exact remaining task texts (unchecked todos from Getting Started)
        required_remaining_texts = [
            "block types",
            "share a page"
        ]
        remaining_contents = [n.get("content", "").lower() for n in emoji_items]
        for required_text in required_remaining_texts:
            if not any(required_text in content for content in remaining_contents):
                errors.append(f"[X] Remaining Tasks missing item with '{required_text}'")
            else:
                checks_passed.append(f"[C] Remaining Tasks has item with '{required_text}'")

        # 7. Check for divider
        divider_found = any(b.get("type") == "divider" for b in gs_blocks_sorted)
        if not divider_found:
            errors.append("[X] Divider not found")
        else:
            checks_passed.append("[C] Divider found")

        # 8. Check for next steps paragraph
        next_steps_found = any(
            b.get("type") == "paragraph" and "next steps" in b.get("content", "").lower()
            for b in gs_blocks_sorted
        )
        if not next_steps_found:
            errors.append("[X] Paragraph about next steps not found")
        else:
            checks_passed.append("[C] Paragraph about next steps found")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: create-bug-tracker-hot-fixes
# Description: Add Hot Fixes section to Bug Tracker with todos and summary callout
# =============================================================================
def _validate_agent_create_bug_tracker_hot_fixes(
    final_state_backend: Backend,
    final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Bug Tracker Hot Fixes section creation."""
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Find Bug Tracker page
    try:
        bug_tracker = _find_page_by_title(final_state_backend, "Bug Tracker")
        if not bug_tracker:
            errors.append("[X] Bug Tracker page not found")
        else:
            checks_passed.append("[C] Bug Tracker page found")

        bt_blocks = _get_blocks_for_page(final_state_backend, bug_tracker.get("_id", ""))
        bt_blocks_sorted = sorted(bt_blocks, key=lambda b: b.get("order", 0))

        # 2. Check Hot Fixes heading exists with 🔥 emoji
        hot_fixes_heading = None
        for b in bt_blocks_sorted:
            if b.get("type") == "heading2" and "hot fixes" in b.get("content", "").lower():
                hot_fixes_heading = b
                break

        if not hot_fixes_heading:
            errors.append("[X] Hot Fixes heading2 not found")
        else:
            checks_passed.append("[C] Hot Fixes heading2 found")

        if "🔥" not in hot_fixes_heading.get("content", ""):
            errors.append("[X] Hot Fixes heading missing 🔥 emoji")
        else:
            checks_passed.append("[C] Hot Fixes heading has 🔥 emoji")

        # 3. Check 3 unchecked todos with required emojis exist
        todos = [b for b in bt_blocks_sorted if b.get("type") == "todo"]
        required_emojis = ["🚨", "⚡", "🛡️"]
        hot_fix_todos = []
        for todo in todos:
            content = todo.get("content", "")
            if any(emoji in content for emoji in required_emojis):
                hot_fix_todos.append(todo)

        if len(hot_fix_todos) < 3:
            errors.append(f"[X] Expected 3 Hot Fixes todos with emojis, found {len(hot_fix_todos)}")
        else:
            checks_passed.append(f"[C] Found 3 Hot Fixes todos with emojis as expected")

        # 4. Check blue callout with summary exists
        callouts = [b for b in bt_blocks_sorted if b.get("type") == "callout"]
        summary_callout = None
        for c in callouts:
            props = c.get("properties", {})
            content = c.get("content", "").lower()
            if "blue" in props.get("backgroundColor", "") and "summary" in content:
                summary_callout = c
                break

        if not summary_callout:
            errors.append("[X] Blue callout with bug summary not found")
        else:
            checks_passed.append("[C] Blue callout with bug summary found")

        # 5. Check callout has 📊 icon
        if summary_callout.get("properties", {}).get("icon") != "📊":
            errors.append("[X] Summary callout missing 📊 icon")
        else:
            checks_passed.append("[C] Summary callout has 📊 icon")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: create-team-directory-employee-section
# Description: Add structured employee sections to Team Directory
# =============================================================================
def _validate_agent_create_team_directory_employee_section(
    final_state_backend: Backend,
    final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Team Directory employee section creation."""
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Find Team Directory page
    try:
        team_dir = _find_page_by_title(final_state_backend, "Team Directory")
        if not team_dir:
            errors.append("[X] Team Directory page not found")
        else:
            checks_passed.append("[C] Team Directory page found")

        td_blocks = _get_blocks_for_page(final_state_backend, team_dir.get("_id", ""))

        # 2. Check Team Members heading exists
        team_members_found = any(
            b.get("type") == "heading2" and "team members" in b.get("content", "").lower()
            for b in td_blocks
        )
        if not team_members_found:
            errors.append("[X] Team Members heading2 not found")
        else:
            checks_passed.append("[C] Team Members heading2 found")

        # 3. Check Engineering Department heading with 🏢
        eng_found = any(
            b.get("type") == "heading3" and "engineering" in b.get("content", "").lower() and "🏢" in b.get("content", "")
            for b in td_blocks
        )
        if not eng_found:
            errors.append("[X] Engineering Department heading3 with 🏢 not found")
        else:
            checks_passed.append("[C] Engineering Department heading3 with 🏢 found")

        # 4. Check blue callout with engineers
        callouts = [b for b in td_blocks if b.get("type") == "callout"]
        blue_callout = None
        for c in callouts:
            if "blue" in c.get("properties", {}).get("backgroundColor", ""):
                blue_callout = c
                break

        if not blue_callout:
            errors.append("[X] Blue callout for Engineering not found")
        else:
            checks_passed.append("[C] Blue callout for Engineering found")

        # 5. Check Design Department heading with 🎨
        design_found = any(
            b.get("type") == "heading3" and "design" in b.get("content", "").lower() and "🎨" in b.get("content", "")
            for b in td_blocks
        )
        if not design_found:
            errors.append("[X] Design Department heading3 with 🎨 not found")
        else:
            checks_passed.append("[C] Design Department heading3 with 🎨 found")

        # 6. Check purple callout
        purple_callout = any(
            "purple" in c.get("properties", {}).get("backgroundColor", "") for c in callouts
        )
        if not purple_callout:
            errors.append("[X] Purple callout for Design not found")
        else:
            checks_passed.append("[C] Purple callout for Design found")

        # 7. Check Team Statistics heading with 📊
        stats_found = any(
            b.get("type") == "heading3" and "statistics" in b.get("content", "").lower()
            for b in td_blocks
        )
        if not stats_found:
            errors.append("[X] Team Statistics heading3 not found")
        else:
            checks_passed.append("[C] Team Statistics heading3 found")

        # 8. Check todo exists
        todo_found = any(b.get("type") == "todo" for b in td_blocks)
        if not todo_found:
            errors.append("[X] Update directory todo not found")
        else:
            checks_passed.append("[C] Update directory todo found")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: create-project-health-dashboard-3-v2
# Description: Create dashboard under Project Roadmap with Q1/Q2 analysis
# =============================================================================
def _validate_agent_create_project_health_dashboard_3(
    final_state_backend: Backend,
    final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Project Health Dashboard creation."""
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Find Project Health Dashboard page
    try:
        dashboard = _find_page_by_title(final_state_backend, "Project Health Dashboard")
        if not dashboard:
            errors.append("[X] Project Health Dashboard page not found")
        else:
            checks_passed.append("[C] Project Health Dashboard page found")

        # 2. Check it's under Project Roadmap
        roadmap = _find_page_by_title(final_state_backend, "Project Roadmap")
        if roadmap and dashboard.get("parentId") != roadmap.get("_id"):
            errors.append("[X] Project Health Dashboard not under Project Roadmap")
        else:
            checks_passed.append("[C] Project Health Dashboard under Project Roadmap")

        db_blocks = _get_blocks_for_page(final_state_backend, dashboard.get("_id", ""))

        # 3. Check heading structure with 🏥 and 📊
        title_found = any(
            b.get("type") == "heading1" and "health dashboard" in b.get("content", "").lower()
            for b in db_blocks
        )
        if not title_found:
            errors.append("[X] Project Health Dashboard heading1 not found")
        else:
            checks_passed.append("[C] Project Health Dashboard heading1 found")

        analysis_heading = any(
            b.get("type") == "heading2" and "q1" in b.get("content", "").lower() and "q2" in b.get("content", "").lower()
            for b in db_blocks
        )
        if not analysis_heading:
            errors.append("[X] Q1 vs Q2 analysis heading2 not found")
        else:
            checks_passed.append("[C] Q1 vs Q2 analysis heading2 found")

        # 4. Check callouts exist (Q1 green, Q2 blue)
        callouts = [b for b in db_blocks if b.get("type") == "callout"]
        if len(callouts) < 2:
            errors.append(f"[X] Expected at least 2 callouts for Q1/Q2, found {len(callouts)}")
        else:
            checks_passed.append(f"[C] Found at least 2 callouts for Q1/Q2 ({len(callouts)})")

        # 5. Check Combined Objectives section with bullets
        combined_found = any(
            b.get("type") == "heading2" and "combined" in b.get("content", "").lower()
            for b in db_blocks
        )
        if not combined_found:
            errors.append("[X] Combined Objectives heading2 not found")
        else:
            checks_passed.append("[C] Combined Objectives heading2 found")

        bullets = [b for b in db_blocks if b.get("type") == "bulletedList"]
        if len(bullets) < 1:
            errors.append("[X] Uncompleted todos bulleted list not found")
        else:
            checks_passed.append("[C] Uncompleted todos bulleted list found")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: create-getting-started-date-header
# Description: Add date header and todos after specific location
# =============================================================================
def _validate_agent_create_getting_started_date_header(
    final_state_backend: Backend,
    final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Getting Started date header creation."""
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Find Getting Started page
    try:
        gs = _find_page_by_title(final_state_backend, "Getting Started")
        if not gs:
            errors.append("[X] Getting Started page not found")
        else:
            checks_passed.append("[C] Getting Started page found")

        gs_blocks = _get_blocks_for_page(final_state_backend, gs.get("_id", ""))

        # 2. Check bold date paragraph with 2024-02-15
        date_found = any(
            b.get("type") == "paragraph" and "2024-02-15" in b.get("content", "")
            for b in gs_blocks
        )
        if not date_found:
            errors.append("[X] Bold paragraph with '2024-02-15' not found")
        else:
            checks_passed.append("[C] Bold paragraph with '2024-02-15' found")

        # 3. Check 3 todos with required emojis
        todos = [b for b in gs_blocks if b.get("type") == "todo"]
        required_emojis = ["🔍", "🏗️", "⚡"]
        found_emojis = 0
        for todo in todos:
            content = todo.get("content", "")
            if any(emoji in content for emoji in required_emojis):
                found_emojis += 1

        if found_emojis < 3:
            errors.append(f"[X] Expected 3 todos with emojis 🔍🏗️⚡, found {found_emojis}")
        else:
            checks_passed.append(f"[C] Found 3 todos with emojis 🔍🏗️⚡ as expected")

        # 4. Check divider exists
        divider_found = any(b.get("type") == "divider" for b in gs_blocks)
        if not divider_found:
            errors.append("[X] Divider not found")
        else:
            checks_passed.append("[C] Divider found")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: create-weekly-standup-priority-updates
# Description: Add Priority Updates section to Weekly Standup Template
# =============================================================================
def _validate_agent_create_weekly_standup_priority_updates(
    final_state_backend: Backend,
    final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Weekly Standup Priority Updates creation."""
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Find Weekly Standup Template page
    try:
        standup = _find_page_by_title(final_state_backend, "Weekly Standup Template")
        if not standup:
            errors.append("[X] Weekly Standup Template page not found")
        else:
            checks_passed.append("[C] Weekly Standup Template page found")

        su_blocks = _get_blocks_for_page(final_state_backend, standup.get("_id", ""))

        # 2. Check Priority Updates heading3 with 🎯
        priority_found = any(
            b.get("type") == "heading3" and "priority updates" in b.get("content", "").lower() and "🎯" in b.get("content", "")
            for b in su_blocks
        )
        if not priority_found:
            errors.append("[X] Priority Updates heading3 with 🎯 not found")
        else:
            checks_passed.append("[C] Priority Updates heading3 with 🎯 found")

        # 3. Check 3 todos with required emojis
        todos = [b for b in su_blocks if b.get("type") == "todo"]
        required_emojis = ["📊", "🔍", "💬"]
        found_emojis = 0
        for todo in todos:
            content = todo.get("content", "")
            if any(emoji in content for emoji in required_emojis):
                found_emojis += 1

        if found_emojis < 3:
            errors.append(f"[X] Expected 3 Priority Updates todos with emojis, found {found_emojis}")
        else:
            checks_passed.append(f"[C] Found 3 Priority Updates todos with emojis as expected")

        # 4. Check yellow callout with ⚡ icon
        callouts = [b for b in su_blocks if b.get("type") == "callout"]
        yellow_callout = None
        for c in callouts:
            if "yellow" in c.get("properties", {}).get("backgroundColor", ""):
                yellow_callout = c
                break

        if not yellow_callout:
            errors.append("[X] Yellow callout not found")
        else:
            checks_passed.append("[C] Yellow callout found")

        if yellow_callout.get("properties", {}).get("icon") != "⚡":
            errors.append("[X] Yellow callout missing ⚡ icon")
        else:
            checks_passed.append("[C] Yellow callout has ⚡ icon")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: create-feature-requests-portal
# Description: Restructure Feature Requests with portal heading and sections
# =============================================================================
def _validate_agent_create_feature_requests_portal(
    final_state_backend: Backend,
    final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Feature Requests Portal creation."""
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Find Feature Requests page
    try:
        fr = _find_page_by_title(final_state_backend, "Feature Requests")
        if not fr:
            errors.append("[X] Feature Requests page not found")
        else:
            checks_passed.append("[C] Feature Requests page found")

        fr_blocks = _get_blocks_for_page(final_state_backend, fr.get("_id", ""))

        # 2. Check portal heading with ✨
        portal_found = any(
            b.get("type") == "heading1" and "feature request portal" in b.get("content", "").lower() and "✨" in b.get("content", "")
            for b in fr_blocks
        )
        if not portal_found:
            errors.append("[X] Feature Request Portal heading1 with ✨ not found")
        else:
            checks_passed.append("[C] Feature Request Portal heading1 with ✨ found")

        # 3. Check green callout with Q3 2024 goal
        callouts = [b for b in fr_blocks if b.get("type") == "callout"]
        green_callout = None
        for c in callouts:
            if "green" in c.get("properties", {}).get("backgroundColor", "") and "q3 2024" in c.get("content", "").lower():
                green_callout = c
                break

        if not green_callout:
            errors.append("[X] Green callout with Q3 2024 goal not found")
        else:
            checks_passed.append("[C] Green callout with Q3 2024 goal found")

        # 4. Check High Priority heading with 🔥
        high_priority_found = any(
            b.get("type") == "heading2" and "high priority" in b.get("content", "").lower() and "🔥" in b.get("content", "")
            for b in fr_blocks
        )
        if not high_priority_found:
            errors.append("[X] High Priority Features heading2 with 🔥 not found")
        else:
            checks_passed.append("[C] High Priority Features heading2 with 🔥 found")

        # 5. Check Community Suggestions heading with 💡
        community_found = any(
            b.get("type") == "heading2" and "community" in b.get("content", "").lower() and "💡" in b.get("content", "")
            for b in fr_blocks
        )
        if not community_found:
            errors.append("[X] Community Suggestions heading2 with 💡 not found")
        else:
            checks_passed.append("[C] Community Suggestions heading2 with 💡 found")

        # 6. Check todos exist (at least 5 for High Priority + 3 for Community = 8)
        todos = [b for b in fr_blocks if b.get("type") == "todo"]
        if len(todos) < 8:
            errors.append(f"[X] Expected at least 8 todos (5 High Priority + 3 Community), found {len(todos)}")
        else:
            checks_passed.append(f"[C] Found at least 8 todos (5 High Priority + 3 Community) ({len(todos)})")

        # 7. Check divider and voting paragraph
        divider_found = any(b.get("type") == "divider" for b in fr_blocks)
        voting_found = any(
            b.get("type") == "paragraph" and "voting" in b.get("content", "").lower()
            for b in fr_blocks
        )

        if not divider_found:
            errors.append("[X] Divider not found")
        else:
            checks_passed.append("[C] Divider found")
        if not voting_found:
            errors.append("[X] Voting instructions paragraph not found")
        else:
            checks_passed.append("[C] Voting instructions paragraph found")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: create-project-goals-analysis
# Description: Create goals analysis page with conditional callout colors
# =============================================================================
def _validate_agent_create_project_goals_analysis(
    final_state_backend: Backend,
    final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Project Goals Analysis creation."""
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Find Project Goals Analysis page
    try:
        analysis = _find_page_by_title(final_state_backend, "Project Goals Analysis")
        if not analysis:
            errors.append("[X] Project Goals Analysis page not found")
        else:
            checks_passed.append("[C] Project Goals Analysis page found")

        # 2. Check it's under Project Roadmap
        roadmap = _find_page_by_title(final_state_backend, "Project Roadmap")
        if roadmap and analysis.get("parentId") != roadmap.get("_id"):
            errors.append("[X] Project Goals Analysis not under Project Roadmap")
        else:
            checks_passed.append("[C] Project Goals Analysis under Project Roadmap")

        an_blocks = _get_blocks_for_page(final_state_backend, analysis.get("_id", ""))

        # 3. Check heading structure
        title_found = any(
            b.get("type") == "heading1" and "goals" in b.get("content", "").lower() and "progress" in b.get("content", "").lower()
            for b in an_blocks
        )
        if not title_found:
            errors.append("[X] Goals Progress Report heading1 not found")
        else:
            checks_passed.append("[C] Goals Progress Report heading1 found")

        summary_found = any(
            b.get("type") == "heading2" and "summary" in b.get("content", "").lower()
            for b in an_blocks
        )
        if not summary_found:
            errors.append("[X] Executive Summary heading2 not found")
        else:
            checks_passed.append("[C] Executive Summary heading2 found")

        # 4. Check paragraph with total count
        total_para = any(
            b.get("type") == "paragraph" and "total" in b.get("content", "").lower()
            for b in an_blocks
        )
        if not total_para:
            errors.append("[X] Total objectives paragraph not found")
        else:
            checks_passed.append("[C] Total objectives paragraph found")

        # 5. Check Q1 and Q2 analysis headings
        q1_found = any(
            b.get("type") == "heading2" and "q1" in b.get("content", "").lower()
            for b in an_blocks
        )
        q2_found = any(
            b.get("type") == "heading2" and "q2" in b.get("content", "").lower()
            for b in an_blocks
        )
        if not q1_found or not q2_found:
            errors.append("[X] Q1 or Q2 Analysis headings not found")
        else:
            checks_passed.append("[C] Q1 or Q2 Analysis headings found")

        # 6. Check callouts exist (should have green for Q1 >=50%, red for Q2 <50%)
        callouts = [b for b in an_blocks if b.get("type") == "callout"]
        if len(callouts) < 2:
            errors.append(f"[X] Expected at least 2 callouts for Q1/Q2, found {len(callouts)}")
        else:
            checks_passed.append(f"[C] Found at least 2 callouts for Q1/Q2 ({len(callouts)})")

        # Check colors (lenient - just verify different colors used)
        colors = [c.get("properties", {}).get("backgroundColor", "") for c in callouts]
        has_green = any("green" in c for c in colors)
        has_red = any("red" in c for c in colors)

        if not has_green:
            errors.append("[X] Green callout for high completion rate not found")
        else:
            checks_passed.append("[C] Green callout for high completion rate found")
        if not has_red:
            errors.append("[X] Red callout for low completion rate not found")
        else:
            checks_passed.append("[C] Red callout for low completion rate found")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: create-team-knowledge-base
# Description: Create Knowledge Base under Company Handbook with source analysis
# =============================================================================
def _validate_agent_create_team_knowledge_base(
    final_state_backend: Backend,
    final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Team Knowledge Base creation."""
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Find Team Knowledge Base page
    try:
        kb = _find_page_by_title(final_state_backend, "Team Knowledge Base")
        if not kb:
            errors.append("[X] Team Knowledge Base page not found")
        else:
            checks_passed.append("[C] Team Knowledge Base page found")

        # 2. Check it's under Company Handbook
        handbook = _find_page_by_title(final_state_backend, "Company Handbook")
        if handbook and kb.get("parentId") != handbook.get("_id"):
            errors.append("[X] Team Knowledge Base not under Company Handbook")
        else:
            checks_passed.append("[C] Team Knowledge Base under Company Handbook")

        kb_blocks = _get_blocks_for_page(final_state_backend, kb.get("_id", ""))

        # 3. Check heading structure
        title_found = any(
            b.get("type") == "heading1" and "knowledge base" in b.get("content", "").lower()
            for b in kb_blocks
        )
        if not title_found:
            errors.append("[X] Team Knowledge Base heading1 not found")
        else:
            checks_passed.append("[C] Team Knowledge Base heading1 found")

        nav_found = any(
            b.get("type") == "heading2" and "navigation" in b.get("content", "").lower()
            for b in kb_blocks
        )
        if not nav_found:
            errors.append("[X] Quick Navigation heading2 not found")
        else:
            checks_passed.append("[C] Quick Navigation heading2 found")

        # 4. Check 3 blue callouts for source pages
        callouts = [b for b in kb_blocks if b.get("type") == "callout"]
        blue_callouts = [c for c in callouts if "blue" in c.get("properties", {}).get("backgroundColor", "")]
        if len(blue_callouts) < 3:
            errors.append(f"[X] Expected 3 blue callouts for source pages, found {len(blue_callouts)}")
        else:
            checks_passed.append(f"[C] Found 3 blue callouts for source pages as expected")

        # 5. Check Documentation Standards heading
        docs_found = any(
            b.get("type") == "heading2" and "documentation" in b.get("content", "").lower()
            for b in kb_blocks
        )
        if not docs_found:
            errors.append("[X] Documentation Standards heading2 not found")
        else:
            checks_passed.append("[C] Documentation Standards heading2 found")

        # 6. Check quote block
        quote_found = any(b.get("type") == "quote" for b in kb_blocks)
        if not quote_found:
            errors.append("[X] Quote block not found")
        else:
            checks_passed.append("[C] Quote block found")

        # 7. Check 5 todos with emojis
        todos = [b for b in kb_blocks if b.get("type") == "todo"]
        if len(todos) < 5:
            errors.append(f"[X] Expected 5 documentation todos, found {len(todos)}")
        else:
            checks_passed.append(f"[C] Found 5 documentation todos as expected")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: create-code-examples-index
# Description: Add repository index to Code Examples page
# =============================================================================
def _validate_agent_create_code_examples_index(
    final_state_backend: Backend,
    final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Code Examples Repository Index creation."""
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Find Code Examples Repository page
    try:
        code_repo = _find_page_by_title(final_state_backend, "Code Examples Repository")
        if not code_repo:
            errors.append("[X] Code Examples Repository page not found")
        else:
            checks_passed.append("[C] Code Examples Repository page found")

        cr_blocks = _get_blocks_for_page(final_state_backend, code_repo.get("_id", ""))

        # 2. Check Repository Index heading with 🗂️
        index_found = any(
            b.get("type") == "heading1" and "repository index" in b.get("content", "").lower() and "🗂️" in b.get("content", "")
            for b in cr_blocks
        )
        if not index_found:
            errors.append("[X] Repository Index heading1 with 🗂️ not found")
        else:
            checks_passed.append("[C] Repository Index heading1 with 🗂️ found")

        # 3. Check Language Coverage heading with 📊
        coverage_found = any(
            b.get("type") == "heading2" and "language" in b.get("content", "").lower() and "coverage" in b.get("content", "").lower()
            for b in cr_blocks
        )
        if not coverage_found:
            errors.append("[X] Language Coverage heading2 not found")
        else:
            checks_passed.append("[C] Language Coverage heading2 found")

        # 4. Check numbered list with languages
        numbered = [b for b in cr_blocks if b.get("type") == "numberedList"]
        if len(numbered) < 1:
            errors.append("[X] Language numbered list not found")
        else:
            checks_passed.append("[C] Language numbered list found")

        # 5. Check Quick Reference heading with gray callout
        quick_ref_found = any(
            b.get("type") == "heading2" and "quick reference" in b.get("content", "").lower()
            for b in cr_blocks
        )
        if not quick_ref_found:
            errors.append("[X] Quick Reference heading2 not found")
        else:
            checks_passed.append("[C] Quick Reference heading2 found")

        # Check gray callout
        callouts = [b for b in cr_blocks if b.get("type") == "callout"]
        gray_callout = any("gray" in c.get("properties", {}).get("backgroundColor", "") for c in callouts)
        if not gray_callout:
            errors.append("[X] Gray callout for Quick Reference not found")
        else:
            checks_passed.append("[C] Gray callout for Quick Reference found")

        # 6. Check Contribution Guidelines heading
        contrib_found = any(
            b.get("type") == "heading3" and "contribution" in b.get("content", "").lower()
            for b in cr_blocks
        )
        if not contrib_found:
            errors.append("[X] Contribution Guidelines heading3 not found")
        else:
            checks_passed.append("[C] Contribution Guidelines heading3 found")

        # 7. Check two dividers exist
        dividers = [b for b in cr_blocks if b.get("type") == "divider"]
        if len(dividers) < 2:
            errors.append(f"[X] Expected at least 2 dividers, found {len(dividers)}")
        else:
            checks_passed.append(f"[C] Found at least 2 dividers ({len(dividers)})")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: create-workspace-analytics-dashboard
# Description: Create root-level analytics dashboard with workspace statistics
# =============================================================================
def _validate_agent_create_workspace_analytics_dashboard(
    final_state_backend: Backend,
    final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Workspace Analytics Dashboard creation."""
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Find Workspace Analytics Dashboard page
    try:
        dashboard = _find_page_by_title(final_state_backend, "Workspace Analytics Dashboard")
        if not dashboard:
            errors.append("[X] Workspace Analytics Dashboard page not found")
        else:
            checks_passed.append("[C] Workspace Analytics Dashboard page found")

        db_blocks = _get_blocks_for_page(final_state_backend, dashboard.get("_id", ""))

        # 2. Check title heading with 📊
        title_found = any(
            b.get("type") == "heading1" and "analytics" in b.get("content", "").lower() and "📊" in b.get("content", "")
            for b in db_blocks
        )
        if not title_found:
            errors.append("[X] Workspace Analytics Dashboard heading1 with 📊 not found")
        else:
            checks_passed.append("[C] Workspace Analytics Dashboard heading1 with 📊 found")

        # 3. Check Content Distribution heading with 📈
        content_found = any(
            b.get("type") == "heading2" and "content" in b.get("content", "").lower() and "distribution" in b.get("content", "").lower()
            for b in db_blocks
        )
        if not content_found:
            errors.append("[X] Content Distribution heading2 not found")
        else:
            checks_passed.append("[C] Content Distribution heading2 found")

        # 4. Check numbered list for top pages
        numbered = [b for b in db_blocks if b.get("type") == "numberedList"]
        if len(numbered) < 5:
            errors.append(f"[X] Expected at least 5 numbered items for top pages, found {len(numbered)}")
        else:
            checks_passed.append(f"[C] Found at least 5 numbered items for top pages ({len(numbered)})")

        # 5. Check Page Type Distribution heading with 🏷️
        type_found = any(
            b.get("type") == "heading2" and "type" in b.get("content", "").lower() and "distribution" in b.get("content", "").lower()
            for b in db_blocks
        )
        if not type_found:
            errors.append("[X] Page Type Distribution heading2 not found")
        else:
            checks_passed.append("[C] Page Type Distribution heading2 found")

        # 6. Check Favorite Pages heading with ⭐
        fav_found = any(
            b.get("type") == "heading2" and "favorite" in b.get("content", "").lower() and "⭐" in b.get("content", "")
            for b in db_blocks
        )
        if not fav_found:
            errors.append("[X] Favorite Pages heading2 with ⭐ not found")
        else:
            checks_passed.append("[C] Favorite Pages heading2 with ⭐ found")

        # 7. Check purple summary callout with 🎉
        callouts = [b for b in db_blocks if b.get("type") == "callout"]
        purple_callout = None
        for c in callouts:
            if "purple" in c.get("properties", {}).get("backgroundColor", ""):
                purple_callout = c
                break

        if not purple_callout:
            errors.append("[X] Purple summary callout not found")
        else:
            checks_passed.append("[C] Purple summary callout found")

        if purple_callout.get("properties", {}).get("icon") != "🎉":
            errors.append("[X] Summary callout missing 🎉 icon")
        else:
            checks_passed.append("[C] Summary callout has 🎉 icon")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: create-sprint-retrospective-dashboard
# Description: Create dashboard under Meeting Notes with completion analysis
# =============================================================================
def _validate_agent_create_sprint_retrospective_dashboard(
    final_state_backend: Backend,
    final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Sprint Retrospective Dashboard creation."""
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Find Sprint Retrospective Dashboard page
    try:
        dashboard = _find_page_by_title(final_state_backend, "Sprint Retrospective Dashboard")
        if not dashboard:
            errors.append("[X] Sprint Retrospective Dashboard page not found")
        else:
            checks_passed.append("[C] Sprint Retrospective Dashboard page found")

        # 2. Check it's under Meeting Notes
        meeting_notes = _find_page_by_title(final_state_backend, "Meeting Notes")
        if meeting_notes and dashboard.get("parentId") != meeting_notes.get("_id"):
            errors.append("[X] Sprint Retrospective Dashboard not under Meeting Notes")
        else:
            checks_passed.append("[C] Sprint Retrospective Dashboard under Meeting Notes")

        db_blocks = _get_blocks_for_page(final_state_backend, dashboard.get("_id", ""))

        # 3. Check title heading with 🔄
        title_found = any(
            b.get("type") == "heading1" and "retrospective" in b.get("content", "").lower() and "🔄" in b.get("content", "")
            for b in db_blocks
        )
        if not title_found:
            errors.append("[X] Sprint Retrospective Dashboard heading1 with 🔄 not found")
        else:
            checks_passed.append("[C] Sprint Retrospective Dashboard heading1 with 🔄 found")

        # 4. Check Action Items Summary heading with ✅
        action_found = any(
            b.get("type") == "heading2" and "action" in b.get("content", "").lower() and "✅" in b.get("content", "")
            for b in db_blocks
        )
        if not action_found:
            errors.append("[X] Action Items Summary heading2 with ✅ not found")
        else:
            checks_passed.append("[C] Action Items Summary heading2 with ✅ found")

        # 5. Check meeting headings exist (heading3)
        meeting_headings = [b for b in db_blocks if b.get("type") == "heading3"]
        if len(meeting_headings) < 2:
            errors.append(f"[X] Expected at least 2 meeting heading3s, found {len(meeting_headings)}")
        else:
            checks_passed.append(f"[C] Found at least 2 meeting heading3s ({len(meeting_headings)})")

        # 6. Check paragraphs with counts
        paras = [b for b in db_blocks if b.get("type") == "paragraph"]
        completed_found = any("completed" in p.get("content", "").lower() for p in paras)
        pending_found = any("pending" in p.get("content", "").lower() for p in paras)

        if not completed_found or not pending_found:
            errors.append("[X] Completed/Pending items paragraphs not found")
        else:
            checks_passed.append("[C] Completed/Pending items paragraphs found")

        # 7. Check Overall Completion Rate heading with 📊
        rate_found = any(
            b.get("type") == "heading2" and "completion" in b.get("content", "").lower() and "rate" in b.get("content", "").lower()
            for b in db_blocks
        )
        if not rate_found:
            errors.append("[X] Overall Completion Rate heading2 not found")
        else:
            checks_passed.append("[C] Overall Completion Rate heading2 found")

        # 8. Check orange callout with 📈 icon
        callouts = [b for b in db_blocks if b.get("type") == "callout"]
        orange_callout = None
        for c in callouts:
            if "orange" in c.get("properties", {}).get("backgroundColor", ""):
                orange_callout = c
                break

        if not orange_callout:
            errors.append("[X] Orange callout not found")
        else:
            checks_passed.append("[C] Orange callout found")

        if orange_callout.get("properties", {}).get("icon") != "📈":
            errors.append("[X] Completion rate callout missing 📈 icon")
        else:
            checks_passed.append("[C] Completion rate callout has 📈 icon")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: weekly-standup-sprint-progress-v2
# Description: Add Sprint Progress Overview to Weekly Standup Template
# =============================================================================
def _validate_weekly_standup_sprint_progress(
    final_state_backend: Backend,
    final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Sprint Progress Overview section in Weekly Standup Template."""
    errors: list[str] = []
    checks_passed: list[str] = []

    try:
        page = _find_page_by_title(final_state_backend, "Weekly Standup Template")
        if not page:
            errors.append("[X] Weekly Standup Template page not found")
        else:
            checks_passed.append("[C] Weekly Standup Template page found")

        blocks = _get_blocks_for_page(final_state_backend, page.get("_id", ""))
        if not blocks:
            errors.append("[X] Page has no blocks")
        else:
            checks_passed.append("[C] Page has blocks")

        if not _has_block_with_content(blocks, "Sprint Progress", "heading2"):
            errors.append("[X] Missing heading '📊 Sprint Progress Overview'")
        else:
            checks_passed.append("[C] has heading '📊 Sprint Progress Overview'")

        if not _has_block_with_content(blocks, "Total tasks tracked"):
            errors.append("[X] Missing paragraph with task counts")
        else:
            checks_passed.append("[C] has paragraph with task counts")

        has_callout = _has_callout_with_bg(blocks, "green") or \
                      _has_callout_with_bg(blocks, "yellow") or \
                      _has_callout_with_bg(blocks, "red")
        if not has_callout:
            errors.append("[X] Missing velocity callout with appropriate background color")
        else:
            checks_passed.append("[C] has velocity callout with appropriate background color")

        if not _has_block_with_content(blocks, "velocity", "callout"):
            errors.append("[X] Missing callout with team velocity text")
        else:
            checks_passed.append("[C] has callout with team velocity text")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: weekly-standup-performance-metrics-v2
# Description: Add Performance Metrics system to Weekly Standup Template
# =============================================================================
def _validate_weekly_standup_performance_metrics(
    final_state_backend: Backend,
    final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Performance Metrics system in Weekly Standup Template."""
    errors: list[str] = []
    checks_passed: list[str] = []

    try:
        page = _find_page_by_title(final_state_backend, "Weekly Standup Template")
        if not page:
            errors.append("[X] Weekly Standup Template page not found")
        else:
            checks_passed.append("[C] Weekly Standup Template page found")

        blocks = _get_blocks_for_page(final_state_backend, page.get("_id", ""))

        if not _has_block_with_content(blocks, "Performance Metrics", "heading2"):
            errors.append("[X] Missing heading '📊 Weekly Performance Metrics'")
        else:
            checks_passed.append("[C] has heading '📊 Weekly Performance Metrics'")

        if not _has_code_block_with_lang(blocks, "javascript"):
            errors.append("[X] Missing JavaScript code block with metrics")
        else:
            checks_passed.append("[C] has JavaScript code block with metrics")

        # Check for todo items - should be unchecked
        new_todos = [b for b in blocks if b.get("type") == "todo" and
                     any(x in b.get("content", "").lower() for x in ["update metrics", "share weekly", "review blocker"])]
        if len(new_todos) < 3:
            errors.append("[X] Missing required todo items for metrics tracking")
        else:
            checks_passed.append("[C] has required todo items for metrics tracking")

        # Verify todos are unchecked (as specified in prompt)
        for todo in new_todos:
            if todo.get("properties", {}).get("checked", False):
                errors.append("[X] Todo items should be unchecked")
            else:
                checks_passed.append("[C] Todo items should be unchecked")

        if not _has_block_type(blocks, "quote"):
            errors.append("[X] Missing quote block at end")
        else:
            checks_passed.append("[C] has quote block at end")

        if not _has_block_type(blocks, "divider"):
            errors.append("[X] Missing divider block")
        else:
            checks_passed.append("[C] has divider block")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: sprint-planning-enhancement-v2
# Description: Enhance Sprint Planning with meeting efficiency metrics
# =============================================================================
def _validate_sprint_planning_enhancement(
    final_state_backend: Backend,
    final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Sprint Planning meeting enhancement."""
    errors: list[str] = []
    checks_passed: list[str] = []

    try:
        page = _find_page_by_title(final_state_backend, "Sprint Planning")
        if not page:
            errors.append("[X] Sprint Planning page not found")
        else:
            checks_passed.append("[C] Sprint Planning page found")

        blocks = _get_blocks_for_page(final_state_backend, page.get("_id", ""))

        if not _has_block_with_content(blocks, "Meeting Efficiency", "heading2"):
            errors.append("[X] Missing heading '⏱️ Meeting Efficiency Metrics'")
        else:
            checks_passed.append("[C] has heading '⏱️ Meeting Efficiency Metrics'")

        if not _has_callout_with_bg(blocks, "blue"):
            errors.append("[X] Missing blue callout with meeting details")
        else:
            checks_passed.append("[C] has blue callout with meeting details")

        if not _has_block_with_content(blocks, "Completion Rate", "heading3"):
            errors.append("[X] Missing heading '📈 Action Item Completion Rate'")
        else:
            checks_passed.append("[C] has heading '📈 Action Item Completion Rate'")

        if not _has_block_with_content(blocks, "Carryover", "heading3"):
            errors.append("[X] Missing heading '🎯 Carryover Items'")
        else:
            checks_passed.append("[C] has heading '🎯 Carryover Items'")

        if not _has_callout_with_bg(blocks, "yellow"):
            errors.append("[X] Missing yellow callout with last updated info")
        else:
            checks_passed.append("[C] has yellow callout with last updated info")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: company-handbook-hybrid-work-v2
# Description: Add Hybrid Work section to Company Handbook
# =============================================================================
def _validate_company_handbook_hybrid_work(
    final_state_backend: Backend,
    final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Hybrid Work section in Company Handbook."""
    errors: list[str] = []
    checks_passed: list[str] = []

    try:
        page = _find_page_by_title(final_state_backend, "Company Handbook")
        if not page:
            errors.append("[X] Company Handbook page not found")
        else:
            checks_passed.append("[C] Company Handbook page found")

        blocks = _get_blocks_for_page(final_state_backend, page.get("_id", ""))

        if not _has_block_with_content(blocks, "Hybrid Work", "heading3"):
            errors.append("[X] Missing heading '🏢 Hybrid Work'")
        else:
            checks_passed.append("[C] has heading '🏢 Hybrid Work'")

        if not _has_block_with_content(blocks, "flexible"):
            errors.append("[X] Missing paragraph about flexible work approach")
        else:
            checks_passed.append("[C] has paragraph about flexible work approach")

        if not _has_callout_with_bg(blocks, "green"):
            errors.append("[X] Missing green callout with work from home policy")
        else:
            checks_passed.append("[C] has green callout with work from home policy")

        hr_todo = _has_block_with_content(blocks, "HR system", "todo") or \
                  _has_block_with_content(blocks, "work location", "todo")
        cal_todo = _has_block_with_content(blocks, "calendar", "todo") or \
                   _has_block_with_content(blocks, "office days", "todo")

        if not hr_todo:
            errors.append("[X] Missing todo about setting work location in HR system")
        else:
            checks_passed.append("[C] has todo about setting work location in HR system")
        if not cal_todo:
            errors.append("[X] Missing todo about updating team calendar")
        else:
            checks_passed.append("[C] has todo about updating team calendar")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: project-guidelines-dividers-v2
# Description: Add dividers and quick navigation to Project Guidelines
# =============================================================================
def _validate_project_guidelines_dividers(
    final_state_backend: Backend,
    final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate dividers after callouts and quick navigation in Project Guidelines."""
    errors: list[str] = []
    checks_passed: list[str] = []

    try:
        page = _find_page_by_title(final_state_backend, "Project Guidelines")
        if not page:
            errors.append("[X] Project Guidelines page not found")
        else:
            checks_passed.append("[C] Project Guidelines page found")

        blocks = _get_blocks_for_page(final_state_backend, page.get("_id", ""))

        if not _has_block_with_content(blocks, "Quick Navigation", "heading2"):
            errors.append("[X] Missing heading '📋 Quick Navigation'")
        else:
            checks_passed.append("[C] has heading '📋 Quick Navigation'")

        if not _has_block_with_content(blocks, "Tips", "numberedList"):
            errors.append("[X] Missing numbered list with callout category counts")
        else:
            checks_passed.append("[C] has numbered list with callout category counts")

        divider_count = _count_blocks_by_type(blocks, "divider")
        if divider_count < 2:
            errors.append(f"[X] Expected multiple dividers, found {divider_count}")
        else:
            checks_passed.append(f"[C] Expected multiple dividers, found {divider_count}")

        if not _has_block_with_content(blocks, "great code comes with guidelines", "quote"):
            errors.append("[X] Missing quote block at end")
        else:
            checks_passed.append("[C] has quote block at end")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: project-roadmap-swap-sections-v2
# Description: Swap sections and add bookmark in Project Roadmap
# =============================================================================
def _validate_project_roadmap_swap_sections(
    final_state_backend: Backend,
    final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate section swap in Project Roadmap."""
    errors: list[str] = []
    checks_passed: list[str] = []

    try:
        page = _find_page_by_title(final_state_backend, "Project Roadmap")
        if not page:
            errors.append("[X] Project Roadmap page not found")
        else:
            checks_passed.append("[C] Project Roadmap page found")

        blocks = _get_blocks_for_page(final_state_backend, page.get("_id", ""))

        # Find positions of quote and Strategic Priorities
        quote_idx = _find_block_index(blocks, "predict the future", "quote")
        priorities_idx = _find_block_index(blocks, "Strategic Priorities", "heading2")

        if quote_idx is None:
            errors.append("[X] Missing quote block about predicting the future")
        else:
            checks_passed.append("[C] has quote block about predicting the future")

        if priorities_idx is None:
            errors.append("[X] Missing Strategic Priorities heading")
        else:
            checks_passed.append("[C] has Strategic Priorities heading")

        # Verify swap: Strategic Priorities should now appear BEFORE quote (they swapped)
        if priorities_idx >= quote_idx:
            errors.append("[X] Sections not swapped - Strategic Priorities should appear before quote")
        else:
            checks_passed.append("[C] Sections swapped - Strategic Priorities should appear before quote")

        # Check bookmark at end with exact URL, caption, and position
        bookmark_found = False
        bookmark_valid = False

        # Find the last non-empty block index
        last_block_idx = len(blocks) - 1

        for idx, b in enumerate(blocks):
            if b.get("type") == "bookmark":
                props = b.get("properties", {})
                url = props.get("url", "")
                caption = props.get("caption", "")

                # Check exact URL
                if "roadmap.productplan.com" in url.lower():
                    bookmark_found = True

                    # Check caption contains expected text
                    if "external roadmap reference" not in caption.lower():
                        errors.append(f"[X] Bookmark caption should be 'External roadmap reference', got: '{caption}'")
                    else:
                        checks_passed.append(f"[C] Bookmark caption should be 'External roadmap reference', got: '{caption}'")

                    # Check bookmark is at the end (last block or close to it)
                    if idx >= last_block_idx - 1:  # Allow for divider after bookmark
                        bookmark_valid = True

        if not bookmark_found:
            errors.append("[X] Missing bookmark with URL 'https://roadmap.productplan.com'")
        else:
            checks_passed.append("[C] has bookmark with URL 'https://roadmap.productplan.com'")

        if not bookmark_valid:
            errors.append("[X] Bookmark should be at the very end of the page")
        else:
            checks_passed.append("[C] Bookmark should be at the very end of the page")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: api-documentation-versioning-v2
# Description: Add API versioning guide to API Documentation
# =============================================================================
def _validate_api_documentation_versioning(
    final_state_backend: Backend,
    final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate API Versioning guide in API Documentation."""
    errors: list[str] = []
    checks_passed: list[str] = []

    try:
        page = _find_page_by_title(final_state_backend, "API Documentation")
        if not page:
            page = _find_page_by_title(final_state_backend, "Engineering Wiki")
        if not page:
            errors.append("[X] Neither API Documentation nor Engineering Wiki page found")
        else:
            checks_passed.append("[C] Neither API Documentation nor Engineering Wiki page found")

        blocks = _get_blocks_for_page(final_state_backend, page.get("_id", ""))

        if not _has_block_with_content(blocks, "Versioning Strategy", "heading2"):
            errors.append("[X] Missing heading '🔄 API Versioning Strategy'")
        else:
            checks_passed.append("[C] has heading '🔄 API Versioning Strategy'")

        if not _has_callout_with_bg(blocks, "blue"):
            errors.append("[X] Missing blue callout about semantic versioning")
        else:
            checks_passed.append("[C] has blue callout about semantic versioning")

        if not _has_block_with_content(blocks, "Version Headers", "heading3"):
            errors.append("[X] Missing heading '📌 Version Headers'")
        else:
            checks_passed.append("[C] has heading '📌 Version Headers'")

        if not _has_code_block_with_lang(blocks, "http"):
            errors.append("[X] Missing HTTP code block with version headers")
        else:
            checks_passed.append("[C] has HTTP code block with version headers")

        if not _has_block_with_content(blocks, "Deprecation Policy", "heading3"):
            errors.append("[X] Missing heading '🚨 Deprecation Policy'")
        else:
            checks_passed.append("[C] has heading '🚨 Deprecation Policy'")

        if not _has_block_type(blocks, "numberedList"):
            errors.append("[X] Missing numbered list with deprecation rules")
        else:
            checks_passed.append("[C] has numbered list with deprecation rules")

        bookmark_found = False
        for b in blocks:
            if b.get("type") == "bookmark":
                props = b.get("properties", {})
                url = props.get("url", "")
                if "semver" in url.lower():
                    bookmark_found = True
                    break

        if not bookmark_found:
            errors.append("[X] Missing bookmark to semver.org")
        else:
            checks_passed.append("[C] has bookmark to semver.org")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: team-directory-cross-page-v2
# Description: Add cross-page project involvement to Team Directory
# =============================================================================
def _validate_team_directory_cross_page(
    final_state_backend: Backend,
    final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate cross-page project involvement in Team Directory."""
    errors: list[str] = []
    checks_passed: list[str] = []

    try:
        page = _find_page_by_title(final_state_backend, "Team Directory")
        if not page:
            errors.append("[X] Team Directory page not found")
        else:
            checks_passed.append("[C] Team Directory page found")

        blocks = _get_blocks_for_page(final_state_backend, page.get("_id", ""))

        if not _has_block_with_content(blocks, "Project Involvement", "heading2"):
            errors.append("[X] Missing heading '📊 Team Project Involvement'")
        else:
            checks_passed.append("[C] has heading '📊 Team Project Involvement'")

        member_headings = 0
        for name in ["Alice", "Bob", "Carol", "Frank"]:
            if _has_block_with_content(blocks, name, "heading3"):
                member_headings += 1

        if member_headings < 2:
            errors.append(f"[X] Expected at least 2 team member headings, found {member_headings}")
        else:
            checks_passed.append(f"[C] Found at least 2 team member headings ({member_headings})")

        if not _has_callout_with_bg(blocks, "purple"):
            errors.append("[X] Missing purple callout about team collaboration")
        else:
            checks_passed.append("[C] has purple callout about team collaboration")

        if not _has_block_type(blocks, "divider"):
            errors.append("[X] Missing divider block")
        else:
            checks_passed.append("[C] has divider block")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: project-status-summary-v2
# Description: Create Project Status Summary page
# =============================================================================
def _validate_project_status_summary(
    final_state_backend: Backend,
    final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Project Status Summary page creation."""
    errors: list[str] = []
    checks_passed: list[str] = []

    try:
        page = _find_page_by_title(final_state_backend, "Project Status Summary")
        if not page:
            errors.append("[X] Project Status Summary page not found")
        else:
            checks_passed.append("[C] Project Status Summary page found")

        parent = _find_page_by_title(final_state_backend, "Project Documentation")
        if parent and page.get("parentId") != parent.get("_id"):
            errors.append("[X] Project Status Summary should be child of Project Documentation")
        else:
            checks_passed.append("[C] Project Status Summary should be child of Project Documentation")

        blocks = _get_blocks_for_page(final_state_backend, page.get("_id", ""))

        if not _has_block_with_content(blocks, "Project Status Summary", "heading1"):
            errors.append("[X] Missing heading '📊 Project Status Summary'")
        else:
            checks_passed.append("[C] has heading '📊 Project Status Summary'")

        if not _has_block_with_content(blocks, "Report Date", "heading2"):
            errors.append("[X] Missing heading '📅 Report Date'")
        else:
            checks_passed.append("[C] has heading '📅 Report Date'")

        if not _has_block_with_content(blocks, "Active Tasks", "heading2"):
            errors.append("[X] Missing heading '🎯 Pages with Active Tasks'")
        else:
            checks_passed.append("[C] has heading '🎯 Pages with Active Tasks'")

        # Check for page analysis: should have heading3s for pages and bulleted lists with stats
        if not _has_block_type(blocks, "heading3"):
            errors.append("[X] Missing heading3 blocks for page titles")
        else:
            checks_passed.append("[C] has heading3 blocks for page titles")

        # Check for bulleted list with completion stats
        has_stats = _has_block_with_content(blocks, "Completed", "bulletedList") or \
                    _has_block_with_content(blocks, "Total tasks", "bulletedList")
        if not has_stats:
            errors.append("[X] Missing bulleted list with task statistics")
        else:
            checks_passed.append("[C] has bulleted list with task statistics")

        if not _has_block_with_content(blocks, "Statistics", "heading2"):
            errors.append("[X] Missing heading '📈 Workspace-wide Statistics'")
        else:
            checks_passed.append("[C] has heading '📈 Workspace-wide Statistics'")

        if not _has_callout_with_bg(blocks, "green"):
            errors.append("[X] Missing green callout with workspace statistics")
        else:
            checks_passed.append("[C] has green callout with workspace statistics")

        if not _has_block_with_content(blocks, "Priority", "heading2") and \
           not _has_block_with_content(blocks, "Focus Areas", "heading2"):
            errors.append("[X] Missing heading '⚠️ Priority Focus Areas'")
        else:
            checks_passed.append("[C] has heading '⚠️ Priority Focus Areas'")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: bug-tracker-analysis-section-v2
# Description: Add Bug Analysis Report section to Bug Tracker
# =============================================================================
def _validate_bug_tracker_analysis_section(
    final_state_backend: Backend,
    final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Bug Analysis Report section in Bug Tracker."""
    errors: list[str] = []
    checks_passed: list[str] = []

    try:
        page = _find_page_by_title(final_state_backend, "Bug Tracker")
        if not page:
            errors.append("[X] Bug Tracker page not found")
        else:
            checks_passed.append("[C] Bug Tracker page found")

        blocks = _get_blocks_for_page(final_state_backend, page.get("_id", ""))

        if not _has_block_with_content(blocks, "Bug Analysis", "heading3"):
            errors.append("[X] Missing heading '📊 Bug Analysis Report'")
        else:
            checks_passed.append("[C] has heading '📊 Bug Analysis Report'")

        if not _has_block_with_content(blocks, "analysis generated"):
            errors.append("[X] Missing paragraph with analysis date")
        else:
            checks_passed.append("[C] has paragraph with analysis date")

        stats_found = _has_block_with_content(blocks, "Total bugs", "bulletedList") or \
                      _has_block_with_content(blocks, "bugs tracked", "bulletedList")
        if not stats_found:
            errors.append("[X] Missing bulleted list with bug statistics")
        else:
            checks_passed.append("[C] has bulleted list with bug statistics")

        if not _has_callout_with_bg(blocks, "orange"):
            errors.append("[X] Missing orange callout with priority focus")
        else:
            checks_passed.append("[C] has orange callout with priority focus")

        if not _has_block_type(blocks, "divider"):
            errors.append("[X] Missing divider block")
        else:
            checks_passed.append("[C] has divider block")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: code-examples-snippet-library-v2
# Description: Add Code Snippet Library to Code Examples Repository
# =============================================================================
def _validate_code_examples_snippet_library(
    final_state_backend: Backend,
    final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Code Snippet Library section in Code Examples Repository."""
    errors: list[str] = []
    checks_passed: list[str] = []

    try:
        page = _find_page_by_title(final_state_backend, "Code Examples")
        if not page:
            errors.append("[X] Code Examples Repository page not found")
        else:
            checks_passed.append("[C] Code Examples Repository page found")

        blocks = _get_blocks_for_page(final_state_backend, page.get("_id", ""))

        if not _has_block_with_content(blocks, "Snippet Library", "heading2"):
            errors.append("[X] Missing heading '🔧 Code Snippet Library'")
        else:
            checks_passed.append("[C] has heading '🔧 Code Snippet Library'")

        if not _has_block_with_content(blocks, "React Hooks", "heading3"):
            errors.append("[X] Missing heading '⚛️ React Hooks Examples'")
        else:
            checks_passed.append("[C] has heading '⚛️ React Hooks Examples'")

        if not _has_code_block_with_lang(blocks, "javascript"):
            errors.append("[X] Missing JavaScript code block")
        else:
            checks_passed.append("[C] has JavaScript code block")

        if not _has_callout_with_bg(blocks, "yellow"):
            errors.append("[X] Missing yellow callout with pro tip")
        else:
            checks_passed.append("[C] has yellow callout with pro tip")

        if not _has_block_with_content(blocks, "CSS", "heading3"):
            errors.append("[X] Missing heading '🎨 CSS Utilities'")
        else:
            checks_passed.append("[C] has heading '🎨 CSS Utilities'")

        if not _has_code_block_with_lang(blocks, "css"):
            errors.append("[X] Missing CSS code block")
        else:
            checks_passed.append("[C] has CSS code block")

        if not _has_block_type(blocks, "divider"):
            errors.append("[X] Missing divider block")
        else:
            checks_passed.append("[C] has divider block")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: feature-requests-prioritization-v2
# Description: Add Prioritization Matrix to Feature Requests
# =============================================================================
def _validate_feature_requests_prioritization(
    final_state_backend: Backend,
    final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Prioritization Matrix in Feature Requests."""
    errors: list[str] = []
    checks_passed: list[str] = []

    try:
        page = _find_page_by_title(final_state_backend, "Feature Requests")
        if not page:
            errors.append("[X] Feature Requests page not found")
        else:
            checks_passed.append("[C] Feature Requests page found")

        blocks = _get_blocks_for_page(final_state_backend, page.get("_id", ""))

        if not _has_block_with_content(blocks, "Prioritization", "heading2"):
            errors.append("[X] Missing heading '🎯 Prioritization Matrix'")
        else:
            checks_passed.append("[C] has heading '🎯 Prioritization Matrix'")

        # Check for scoring format: Impact, Effort, and Score
        has_impact = _has_block_with_content(blocks, "Impact")
        has_effort = _has_block_with_content(blocks, "Effort")
        has_score = _has_block_with_content(blocks, "Score")
        if not (has_impact and has_effort and has_score):
            errors.append("[X] Missing prioritization matrix with Impact/Effort/Score format")
        else:
            checks_passed.append("[C] has prioritization matrix with Impact/Effort/Score format")

        if not _has_callout_with_bg(blocks, "purple"):
            errors.append("[X] Missing purple callout with top priority")
        else:
            checks_passed.append("[C] has purple callout with top priority")

        # Check for todos
        if not _has_block_type(blocks, "todo"):
            errors.append("[X] Missing todo blocks")
        else:
            checks_passed.append("[C] has todo blocks")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: code-examples-quick-navigation-v2
# Description: Add Quick Navigation and Code Statistics to Code Examples
# =============================================================================
def _validate_code_examples_quick_navigation(
    final_state_backend: Backend,
    final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Quick Navigation and Code Statistics in Code Examples."""
    errors: list[str] = []
    checks_passed: list[str] = []

    try:
        page = _find_page_by_title(final_state_backend, "Code Examples")
        if not page:
            errors.append("[X] Code Examples Repository page not found")
        else:
            checks_passed.append("[C] Code Examples Repository page found")

        blocks = _get_blocks_for_page(final_state_backend, page.get("_id", ""))

        if not _has_block_with_content(blocks, "Quick Navigation", "heading2"):
            errors.append("[X] Missing heading '🔍 Quick Navigation'")
        else:
            checks_passed.append("[C] has heading '🔍 Quick Navigation'")

        if not _has_callout_with_bg(blocks, "blue"):
            errors.append("[X] Missing blue callout with jump links")
        else:
            checks_passed.append("[C] has blue callout with jump links")

        if not _has_block_with_content(blocks, "Code Statistics", "heading2"):
            errors.append("[X] Missing heading '📊 Code Statistics'")
        else:
            checks_passed.append("[C] has heading '📊 Code Statistics'")

        stats_found = _has_block_with_content(blocks, "Total code examples") or \
                      _has_block_with_content(blocks, "Languages covered")
        if not stats_found:
            errors.append("[X] Missing paragraph with code statistics")
        else:
            checks_passed.append("[C] has paragraph with code statistics")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: code-examples-python-section-v2
# Description: Add Python Advanced Patterns section to Code Examples
# =============================================================================
def _validate_code_examples_python_section(
    final_state_backend: Backend,
    final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Python Advanced Patterns section in Code Examples."""
    errors: list[str] = []
    checks_passed: list[str] = []

    try:
        page = _find_page_by_title(final_state_backend, "Code Examples")
        if not page:
            errors.append("[X] Code Examples Repository page not found")
        else:
            checks_passed.append("[C] Code Examples Repository page found")

        blocks = _get_blocks_for_page(final_state_backend, page.get("_id", ""))

        if not _has_block_with_content(blocks, "Python", "heading2"):
            errors.append("[X] Missing heading '🐍 Python Advanced Patterns'")
        else:
            checks_passed.append("[C] has heading '🐍 Python Advanced Patterns'")

        python_blocks = 0
        for b in blocks:
            if b.get("type") == "code":
                props = b.get("properties", {})
                if "python" in props.get("language", "").lower():
                    python_blocks += 1

        if python_blocks < 2:
            errors.append(f"[X] Expected at least 2 Python code blocks, found {python_blocks}")
        else:
            checks_passed.append(f"[C] Found at least 2 Python code blocks ({python_blocks})")

        if not _has_block_with_content(blocks, "Singleton") and \
           not _has_block_with_content(blocks, "singleton"):
            errors.append("[X] Missing Singleton pattern code or description")
        else:
            checks_passed.append("[C] has Singleton pattern code or description")

        if not _has_block_with_content(blocks, "batch") and \
           not _has_block_with_content(blocks, "async"):
            errors.append("[X] Missing async batch processing code or description")
        else:
            checks_passed.append("[C] has async batch processing code or description")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: company-handbook-swap-sections-v2
# Description: Swap sections in Company Handbook
# =============================================================================
def _validate_company_handbook_swap_sections(
    final_state_backend: Backend,
    final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate section swap in Company Handbook."""
    errors: list[str] = []
    checks_passed: list[str] = []

    try:
        page = _find_page_by_title(final_state_backend, "Company Handbook")
        if not page:
            errors.append("[X] Company Handbook page not found")
        else:
            checks_passed.append("[C] Company Handbook page found")

        blocks = _get_blocks_for_page(final_state_backend, page.get("_id", ""))

        benefits_idx = _find_block_index(blocks, "Benefits", "heading2")
        policies_idx = _find_block_index(blocks, "Work Policies", "heading2")

        if benefits_idx is None:
            errors.append("[X] Benefits heading not found")
        else:
            checks_passed.append("[C] Benefits heading found")
        if policies_idx is None:
            errors.append("[X] Work Policies heading not found")
        else:
            checks_passed.append("[C] Work Policies heading found")

        # Verify swap: Benefits should now appear BEFORE Work Policies
        if benefits_idx >= policies_idx:
            errors.append("[X] Sections not swapped - Benefits should appear before Work Policies")
        else:
            checks_passed.append("[C] Sections swapped - Benefits should appear before Work Policies")

        if not _has_callout_with_bg(blocks, "yellow"):
            errors.append("[X] Missing yellow callout with new benefit announcement")
        else:
            checks_passed.append("[C] has yellow callout with new benefit announcement")

        if not _has_block_with_content(blocks, "mental health", "numberedList"):
            errors.append("[X] Missing numbered list item about mental health support")
        else:
            checks_passed.append("[C] has numbered list item about mental health support")

        bookmark_found = False
        for b in blocks:
            if b.get("type") == "bookmark":
                props = b.get("properties", {})
                url = props.get("url", "")
                if "policies" in url.lower() or "company.com" in url.lower():
                    bookmark_found = True
                    break

        if not bookmark_found:
            errors.append("[X] Missing bookmark to policy documentation")
        else:
            checks_passed.append("[C] has bookmark to policy documentation")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: onboarding-guide-progress-tracker-v2
# Description: Add Progress Tracker to Onboarding Guide
# =============================================================================
def _validate_onboarding_guide_progress_tracker(
    final_state_backend: Backend,
    final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Progress Tracker in Onboarding Guide."""
    errors: list[str] = []
    checks_passed: list[str] = []

    try:
        page = _find_page_by_title(final_state_backend, "Onboarding Guide")
        if not page:
            errors.append("[X] Onboarding Guide page not found")
        else:
            checks_passed.append("[C] Onboarding Guide page found")

        blocks = _get_blocks_for_page(final_state_backend, page.get("_id", ""))

        if not _has_block_with_content(blocks, "Progress Tracker", "heading2"):
            errors.append("[X] Missing heading '📈 Progress Tracker'")
        else:
            checks_passed.append("[C] has heading '📈 Progress Tracker'")

        numbered_count = _count_blocks_by_type(blocks, "numberedList")
        if numbered_count < 5:
            errors.append(f"[X] Expected at least 5 numbered list items, found {numbered_count}")
        else:
            checks_passed.append(f"[C] Found at least 5 numbered list items ({numbered_count})")

        if not _has_callout_with_bg(blocks, "green"):
            errors.append("[X] Missing green callout with completion tip")
        else:
            checks_passed.append("[C] has green callout with completion tip")

        if not _has_block_with_content(blocks, "30-Day", "heading2") and \
           not _has_block_with_content(blocks, "Milestones", "heading2"):
            errors.append("[X] Missing heading '🎯 30-Day Milestones'")
        else:
            checks_passed.append("[C] has heading '🎯 30-Day Milestones'")

        milestone_todos = [b for b in blocks if b.get("type") == "todo" and
                           any(x in b.get("content", "").lower() for x in ["code review", "documentation", "standup"])]
        if len(milestone_todos) < 3:
            errors.append("[X] Missing 3 milestone todo items")
        else:
            checks_passed.append("[C] has 3 milestone todo items")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: project-guidelines-testing-section-v2
# Description: Add Testing Best Practices section to Project Guidelines
# =============================================================================
def _validate_project_guidelines_testing_section(
    final_state_backend: Backend,
    final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Testing Best Practices section in Project Guidelines."""
    errors: list[str] = []
    checks_passed: list[str] = []

    try:
        page = _find_page_by_title(final_state_backend, "Project Guidelines")
        if not page:
            errors.append("[X] Project Guidelines page not found")
        else:
            checks_passed.append("[C] Project Guidelines page found")

        blocks = _get_blocks_for_page(final_state_backend, page.get("_id", ""))

        if not _has_block_with_content(blocks, "Testing Best Practices", "heading2"):
            errors.append("[X] Missing heading '📋 Testing Best Practices'")
        else:
            checks_passed.append("[C] has heading '📋 Testing Best Practices'")

        testing_rules = [b for b in blocks if b.get("type") == "numberedList" and
                         any(x in b.get("content", "").lower() for x in ["test", "coverage", "given-when-then"])]
        if len(testing_rules) < 3:
            errors.append("[X] Missing 3 numbered list items with testing rules")
        else:
            checks_passed.append("[C] has 3 numbered list items with testing rules")

        if not _has_callout_with_bg(blocks, "purple"):
            errors.append("[X] Missing purple callout with review requirement")
        else:
            checks_passed.append("[C] has purple callout with review requirement")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: q1-progress-report-v2
# Description: Create Q1 Progress Report page
# =============================================================================
def _validate_q1_progress_report(
    final_state_backend: Backend,
    final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Q1 Progress Report page creation."""
    errors: list[str] = []
    checks_passed: list[str] = []

    try:
        page = _find_page_by_title(final_state_backend, "Q1 Progress Report")
        if not page:
            errors.append("[X] Q1 Progress Report page not found")
        else:
            checks_passed.append("[C] Q1 Progress Report page found")

        q1_goals = _find_page_by_title(final_state_backend, "Q1 Goals")
        if q1_goals and page.get("parentId") != q1_goals.get("_id"):
            errors.append("[X] Q1 Progress Report should be child of Q1 Goals")
        else:
            checks_passed.append("[C] Q1 Progress Report should be child of Q1 Goals")

        blocks = _get_blocks_for_page(final_state_backend, page.get("_id", ""))

        if not _has_block_with_content(blocks, "Progress Report", "heading1"):
            errors.append("[X] Missing heading '📊 Q1 2024 Progress Report'")
        else:
            checks_passed.append("[C] has heading '📊 Q1 2024 Progress Report'")

        if not _has_block_with_content(blocks, "Executive Summary", "heading2"):
            errors.append("[X] Missing heading '✅ Executive Summary'")
        else:
            checks_passed.append("[C] has heading '✅ Executive Summary'")

        if not _has_block_with_content(blocks, "completion"):
            errors.append("[X] Missing paragraph with completion percentage")
        else:
            checks_passed.append("[C] has paragraph with completion percentage")

        if not _has_block_with_content(blocks, "Breakdown", "heading2"):
            errors.append("[X] Missing heading '🎯 Detailed Breakdown'")
        else:
            checks_passed.append("[C] has heading '🎯 Detailed Breakdown'")

        # Check for completed items (quote with ✓) or in-progress items (orange callout with "In Progress")
        has_completed_quotes = _has_block_with_content(blocks, "✓", "quote")
        has_inprogress_callouts = _has_block_with_content(blocks, "In Progress", "callout") or \
                                  _has_block_with_content(blocks, "⏳", "callout")
        if not has_completed_quotes and not has_inprogress_callouts:
            errors.append("[X] Missing quote blocks with ✓ for completed items or callouts with 'In Progress' text")
        else:
            checks_passed.append("[C] has quote blocks with ✓ for completed items or callouts with 'In Progress' text")

        if not _has_block_with_content(blocks, "Key Dates", "heading2"):
            errors.append("[X] Missing heading '📅 Key Dates'")
        else:
            checks_passed.append("[C] has heading '📅 Key Dates'")

        # Check for numbered list with key dates
        if not _has_block_type(blocks, "numberedList"):
            errors.append("[X] Missing numbered list with key dates")
        else:
            checks_passed.append("[C] has numbered list with key dates")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: getting-started-advanced-features-v2
# Description: Add Advanced Features section to Getting Started
# =============================================================================
def _validate_getting_started_advanced_features(
    final_state_backend: Backend,
    final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Advanced Features section in Getting Started."""
    errors: list[str] = []
    checks_passed: list[str] = []

    try:
        page = _find_page_by_title(final_state_backend, "Getting Started")
        if not page:
            errors.append("[X] Getting Started page not found")
        else:
            checks_passed.append("[C] Getting Started page found")

        blocks = _get_blocks_for_page(final_state_backend, page.get("_id", ""))

        if not _has_block_with_content(blocks, "Advanced Features", "heading2"):
            errors.append("[X] Missing heading '🚀 Advanced Features'")
        else:
            checks_passed.append("[C] has heading '🚀 Advanced Features'")

        if not _has_callout_with_bg(blocks, "purple"):
            errors.append("[X] Missing purple callout with pro tip")
        else:
            checks_passed.append("[C] has purple callout with pro tip")

        feature_items = [b for b in blocks if b.get("type") == "numberedList" and
                         any(x in b.get("content", "").lower() for x in ["keyboard", "block", "permission", "shortcut", "sync"])]
        if len(feature_items) < 3:
            errors.append("[X] Missing 3 numbered list items with advanced features")
        else:
            checks_passed.append("[C] has 3 numbered list items with advanced features")

        if not _has_block_type(blocks, "divider"):
            errors.append("[X] Missing divider block")
        else:
            checks_passed.append("[C] has divider block")

        if not _has_block_with_content(blocks, "tutorial", "todo"):
            errors.append("[X] Missing todo about completing advanced features tutorial")
        else:
            checks_passed.append("[C] has todo about completing advanced features tutorial")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: getting-started-date-header-v2
# Description: Add Progress Update January 2024 section to Getting Started
# =============================================================================
def _validate_getting_started_date_header(
    final_state_backend: Backend,
    final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Progress Update January 2024 section in Getting Started."""
    errors: list[str] = []
    checks_passed: list[str] = []

    try:
        page = _find_page_by_title(final_state_backend, "Getting Started")
        if not page:
            errors.append("[X] Getting Started page not found")
        else:
            checks_passed.append("[C] Getting Started page found")

        blocks = _get_blocks_for_page(final_state_backend, page.get("_id", ""))

        if not _has_block_with_content(blocks, "Progress Update", "heading3"):
            errors.append("[X] Missing heading '📅 Progress Update - January 2024'")
        else:
            checks_passed.append("[C] has heading '📅 Progress Update - January 2024'")

        setup_todos = [b for b in blocks if b.get("type") == "todo" and
                       any(x in b.get("content", "").lower() for x in ["workspace usage", "backup", "email notification"])]
        if len(setup_todos) < 3:
            errors.append("[X] Missing 3 new setup todo items")
        else:
            checks_passed.append("[C] has 3 new setup todo items")

        if not _has_block_type(blocks, "divider"):
            errors.append("[X] Missing divider block")
        else:
            checks_passed.append("[C] has divider block")

        if not _has_callout_with_bg(blocks, "yellow"):
            errors.append("[X] Missing yellow callout with setup tip")
        else:
            checks_passed.append("[C] has yellow callout with setup tip")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: weekly-standup-week-tracking-v2
# Description: Add week-over-week tracking to Weekly Standup Template
# =============================================================================
def _validate_weekly_standup_week_tracking(
    final_state_backend: Backend,
    final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Week-over-Week Tracking in Weekly Standup Template."""
    errors: list[str] = []
    checks_passed: list[str] = []

    try:
        page = _find_page_by_title(final_state_backend, "Weekly Standup Template")
        if not page:
            errors.append("[X] Weekly Standup Template page not found")
        else:
            checks_passed.append("[C] Weekly Standup Template page found")

        blocks = _get_blocks_for_page(final_state_backend, page.get("_id", ""))

        if not _has_block_with_content(blocks, "Weekly Progress", "heading2"):
            errors.append("[X] Missing heading '📈 Weekly Progress Tracking'")
        else:
            checks_passed.append("[C] has heading '📈 Weekly Progress Tracking'")

        if not _has_block_with_content(blocks, "Week of", "heading3"):
            errors.append("[X] Missing heading '🗓️ Week of [date]'")
        else:
            checks_passed.append("[C] has heading '🗓️ Week of [date]'")

        if not _has_callout_with_bg(blocks, "yellow"):
            errors.append("[X] Missing yellow callout with Friday reminder")
        else:
            checks_passed.append("[C] has yellow callout with Friday reminder")

        if not _has_block_with_content(blocks, "Completed", "heading3"):
            errors.append("[X] Missing heading '✅ Completed This Week'")
        else:
            checks_passed.append("[C] has heading '✅ Completed This Week'")

        if not _has_block_with_content(blocks, "Carried Over", "heading3"):
            errors.append("[X] Missing heading '🔄 Carried Over'")
        else:
            checks_passed.append("[C] has heading '🔄 Carried Over'")

        if not _has_block_with_content(blocks, "Stats", "heading3"):
            errors.append("[X] Missing heading '📊 Week Stats'")
        else:
            checks_passed.append("[C] has heading '📊 Week Stats'")

        if not _has_block_with_content(blocks, "Next Week", "heading3"):
            errors.append("[X] Missing heading '🎯 Next Week Planning'")
        else:
            checks_passed.append("[C] has heading '🎯 Next Week Planning'")

        planning_todos = [b for b in blocks if b.get("type") == "todo" and
                          any(x in b.get("content", "").lower() for x in ["sprint goals", "backlog", "stakeholder"])]
        if len(planning_todos) < 3:
            errors.append("[X] Missing 3 planning todo items for next week")
        else:
            checks_passed.append("[C] has 3 planning todo items for next week")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: feature-requests-priority-system-v2
# Description: Add priority and categorization system to Feature Requests
# =============================================================================
def _validate_feature_requests_priority_system(
    final_state_backend: Backend,
    final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Priority and Categorization System in Feature Requests."""
    errors: list[str] = []
    checks_passed: list[str] = []

    try:
        page = _find_page_by_title(final_state_backend, "Feature Requests")
        if not page:
            errors.append("[X] Feature Requests page not found")
        else:
            checks_passed.append("[C] Feature Requests page found")

        blocks = _get_blocks_for_page(final_state_backend, page.get("_id", ""))

        if not _has_block_with_content(blocks, "Priority Matrix", "heading2"):
            errors.append("[X] Missing heading '🎯 Feature Priority Matrix'")
        else:
            checks_passed.append("[C] has heading '🎯 Feature Priority Matrix'")

        if not _has_callout_with_bg(blocks, "orange"):
            errors.append("[X] Missing orange callout with feature request count")
        else:
            checks_passed.append("[C] has orange callout with feature request count")

        critical_found = _has_block_with_content(blocks, "Critical", "heading3")
        medium_found = _has_block_with_content(blocks, "Medium", "heading3")
        nice_found = _has_block_with_content(blocks, "Nice", "heading3")

        if not critical_found:
            errors.append("[X] Missing '🔴 Critical Priority' heading")
        else:
            checks_passed.append("[C] has '🔴 Critical Priority' heading")
        if not medium_found:
            errors.append("[X] Missing '🟡 Medium Priority' heading")
        else:
            checks_passed.append("[C] has '🟡 Medium Priority' heading")
        if not nice_found:
            errors.append("[X] Missing '🟢 Nice to Have' heading")
        else:
            checks_passed.append("[C] has '🟢 Nice to Have' heading")

        if not _has_block_with_content(blocks, "Statistics", "heading2"):
            errors.append("[X] Missing heading '📊 Feature Statistics'")
        else:
            checks_passed.append("[C] has heading '📊 Feature Statistics'")

        # Check for numbered list with percentages
        if not _has_block_with_content(blocks, "%", "numberedList"):
            errors.append("[X] Missing numbered list with percentage statistics")
        else:
            checks_passed.append("[C] has numbered list with percentage statistics")

        if not _has_block_with_content(blocks, "Tags", "heading3"):
            errors.append("[X] Missing heading '🏷️ Feature Tags'")
        else:
            checks_passed.append("[C] has heading '🏷️ Feature Tags'")

        # Check for bulleted list under tags
        if not _has_block_type(blocks, "bulletedList"):
            errors.append("[X] Missing bulleted list with feature tags")
        else:
            checks_passed.append("[C] has bulleted list with feature tags")

        if not _has_block_with_content(blocks, "good idea", "quote") and \
           not _has_block_with_content(blocks, "Linus Pauling", "quote"):
            errors.append("[X] Missing quote block at end")
        else:
            checks_passed.append("[C] has quote block at end")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Elvis Batch 3 Tasks - January 2026
# =============================================================================

# =============================================================================
# Task: add-advanced-tasks-to-getting-started-v2
# =============================================================================
def _validate_add_advanced_tasks_to_getting_started(
    final_state_backend: Backend,
    final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate advanced tasks section added to Getting Started page."""
    errors: list[str] = []
    checks_passed: list[str] = []

    # Find Getting Started page
    try:
        page = _find_page_by_title(final_state_backend, "Getting Started")
        if not page:
            errors.append("[X] Getting Started page not found")
        else:
            checks_passed.append("[C] Getting Started page found")

        blocks = _get_blocks_for_page(final_state_backend, page.get("_id", ""))
        blocks_sorted = sorted(blocks, key=lambda b: b.get("order", 0))

        # Check for divider block
        if not _has_block_type(blocks, "divider"):
            errors.append("[X] Missing divider block")
        else:
            checks_passed.append("[C] has divider block")

        # Check for heading_3 with 'Advanced Tasks'
        if not _has_block_with_content(blocks, "Advanced Tasks", "heading3"):
            errors.append("[X] Missing heading_3 '🏆 Advanced Tasks'")
        else:
            checks_passed.append("[C] has heading_3 '🏆 Advanced Tasks'")

        # Check for 3 unchecked todos with specific content
        todos = [b for b in blocks if b.get("type") == "todo"]
        required_todos = ["dashboard", "integrations", "production"]
        found_todos = 0
        for todo in todos:
            content = todo.get("content", "").lower()
            for req in required_todos:
                if req in content:
                    found_todos += 1
                    break

        if found_todos < 3:
            errors.append(f"[X] Missing required todo items (found {found_todos}/3)")
        else:
            checks_passed.append(f"[C] has required todo items (found {found_todos}/3)")

        # Check for yellow callout with ⚡
        has_yellow_callout = False
        for b in blocks:
            if b.get("type") == "callout":
                props = b.get("properties", {})
                bg = props.get("backgroundColor", "")
                icon = props.get("icon", "")
                content = b.get("content", "").lower()
                if "yellow" in bg.lower() and ("⚡" in icon or "tip" in content):
                    has_yellow_callout = True
                    break

        if not has_yellow_callout:
            errors.append("[X] Missing yellow callout with ⚡ icon and tip text")
        else:
            checks_passed.append("[C] has yellow callout with ⚡ icon and tip text")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: comprehensive-getting-started-update-v2
# =============================================================================
def _validate_comprehensive_getting_started_update(
    final_state_backend: Backend,
    final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate comprehensive update to Getting Started page."""
    errors: list[str] = []
    checks_passed: list[str] = []

    try:
        page = _find_page_by_title(final_state_backend, "Getting Started")
        if not page:
            errors.append("[X] Getting Started page not found")
        else:
            checks_passed.append("[C] Getting Started page found")

        blocks = _get_blocks_for_page(final_state_backend, page.get("_id", ""))

        # Check for yellow callout with 'Pro tip' or keyboard shortcuts
        has_pro_tip = False
        for b in blocks:
            if b.get("type") == "callout":
                props = b.get("properties", {})
                bg = props.get("backgroundColor", "")
                content = b.get("content", "").lower()
                if "yellow" in bg.lower() and ("pro tip" in content or "keyboard" in content):
                    has_pro_tip = True
                    break

        if not has_pro_tip:
            errors.append("[X] Missing yellow callout with Pro tip about keyboard shortcuts")
        else:
            checks_passed.append("[C] has yellow callout with Pro tip about keyboard shortcuts")

        # Check for Quick Links heading
        if not _has_block_with_content(blocks, "Quick Links", "heading2"):
            errors.append("[X] Missing heading_2 '🔗 Quick Links'")
        else:
            checks_passed.append("[C] has heading_2 '🔗 Quick Links'")

        # Check for 3 bookmark blocks
        bookmarks = [b for b in blocks if b.get("type") == "bookmark"]
        if len(bookmarks) < 3:
            errors.append(f"[X] Missing bookmark blocks (found {len(bookmarks)}/3)")
        else:
            checks_passed.append(f"[C] has bookmark blocks (found {len(bookmarks)}/3)")

        # Check for paragraph mentioning features/productivity
        if not _has_block_with_content(blocks, "features", "paragraph") and \
           not _has_block_with_content(blocks, "productivity", "paragraph"):
            errors.append("[X] Missing feature count paragraph")
        else:
            checks_passed.append("[C] has feature count paragraph")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: feature-requests-prioritization-system-v2
# =============================================================================
def _validate_feature_requests_prioritization_system(
    final_state_backend: Backend,
    final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate prioritization system on Feature Requests page."""
    errors: list[str] = []
    checks_passed: list[str] = []

    try:
        page = _find_page_by_title(final_state_backend, "Feature Requests")
        if not page:
            errors.append("[X] Feature Requests page not found")
        else:
            checks_passed.append("[C] Feature Requests page found")

        blocks = _get_blocks_for_page(final_state_backend, page.get("_id", ""))

        # Check for callouts with priority indicators
        callouts = [b for b in blocks if b.get("type") == "callout"]
        has_high_priority = any("high" in b.get("content", "").lower() or
                               "⭐" in b.get("properties", {}).get("icon", "")
                               for b in callouts)
        has_medium_priority = any("medium" in b.get("content", "").lower() or
                                 "⚡" in b.get("properties", {}).get("icon", "")
                                 for b in callouts)

        if not has_high_priority and not has_medium_priority:
            errors.append("[X] Missing priority callouts (yellow/⭐ for high, orange/⚡ for medium)")
        else:
            checks_passed.append("[C] has priority callouts (yellow/⭐ for high, orange/⚡ for medium)")

        # Check for divider
        if not _has_block_type(blocks, "divider"):
            errors.append("[X] Missing divider block")
        else:
            checks_passed.append("[C] has divider block")

        # Check for Request Summary heading
        if not _has_block_with_content(blocks, "Summary", "heading2") and \
           not _has_block_with_content(blocks, "Request Summary", "heading2"):
            errors.append("[X] Missing '📊 Request Summary' heading")
        else:
            checks_passed.append("[C] has '📊 Request Summary' heading")

        # Check for summary paragraph with counts
        has_summary = any(
            b.get("type") == "paragraph" and
            ("total" in b.get("content", "").lower() or "priority" in b.get("content", "").lower())
            for b in blocks
        )
        if not has_summary:
            errors.append("[X] Missing summary paragraph with counts")
        else:
            checks_passed.append("[C] has summary paragraph with counts")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: create-code-language-statistics-v2
# =============================================================================
def _validate_create_code_language_statistics(
    final_state_backend: Backend,
    final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Code Language Statistics page creation."""
    errors: list[str] = []
    checks_passed: list[str] = []

    # Find the new statistics page
    try:
        page = _find_page_by_title(final_state_backend, "Code Language Statistics")
        if not page:
            errors.append("[X] Code Language Statistics page not found")
        else:
            checks_passed.append("[C] Code Language Statistics page found")

        # Check for 📈 icon
        if page.get("icon") != "📈":
            errors.append("[X] Page does not have 📈 icon")
        else:
            checks_passed.append("[C] Page has 📈 icon")

        # Check sibling relationship with Code Examples Repository
        code_examples = _find_page_by_title(final_state_backend, "Code Examples Repository")
        if code_examples:
            if page.get("parentId") != code_examples.get("parentId"):
                errors.append("[X] Code Language Statistics is not a sibling of Code Examples Repository")
            else:
                checks_passed.append("[C] Code Language Statistics is a sibling of Code Examples Repository")

        blocks = _get_blocks_for_page(final_state_backend, page.get("_id", ""))

        # Check for required headings
        if not _has_block_with_content(blocks, "Programming Language", "heading1") and \
           not _has_block_with_content(blocks, "Distribution", "heading1"):
            errors.append("[X] Missing heading_1 for Programming Language Distribution")
        else:
            checks_passed.append("[C] has heading_1 for Programming Language Distribution")

        if not _has_block_with_content(blocks, "Language Count", "heading2"):
            errors.append("[X] Missing heading_2 '🔢 Language Count'")
        else:
            checks_passed.append("[C] has heading_2 '🔢 Language Count'")

        # Check for total languages paragraph
        if not _has_block_with_content(blocks, "Total languages", "paragraph") and \
           not _has_block_with_content(blocks, "languages covered", "paragraph"):
            errors.append("[X] Missing paragraph with total language count")
        else:
            checks_passed.append("[C] has paragraph with total language count")

        # Check for Language Breakdown heading
        if not _has_block_with_content(blocks, "Language Breakdown", "heading2") and \
           not _has_block_with_content(blocks, "Breakdown", "heading2"):
            errors.append("[X] Missing heading_2 '📝 Language Breakdown'")
        else:
            checks_passed.append("[C] has heading_2 '📝 Language Breakdown'")

        # Check for bulleted list items
        bullet_items = [b for b in blocks if b.get("type") == "bulletedList"]
        if len(bullet_items) < 1:
            errors.append("[X] Missing bulleted list for language breakdown")
        else:
            checks_passed.append("[C] has bulleted list for language breakdown")

        # Check for Most Documented Language section
        if not _has_block_with_content(blocks, "Most Documented", "heading2"):
            errors.append("[X] Missing heading_2 '🏆 Most Documented Language'")
        else:
            checks_passed.append("[C] has heading_2 '🏆 Most Documented Language'")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: design-system-documentation-audit-v2
# =============================================================================
def _validate_design_system_documentation_audit(
    final_state_backend: Backend,
    final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Design System Audit page creation."""
    errors: list[str] = []
    checks_passed: list[str] = []

    # Find the audit page
    try:
        page = _find_page_by_title(final_state_backend, "Design System Audit")
        if not page:
            errors.append("[X] Design System Audit page not found")
        else:
            checks_passed.append("[C] Design System Audit page found")

        # Check sibling relationship with Design System page
        design_system = _find_page_by_title(final_state_backend, "Design System")
        if design_system:
            if page.get("parentId") != design_system.get("parentId"):
                errors.append("[X] Design System Audit is not a sibling of Design System")
            else:
                checks_passed.append("[C] Design System Audit is a sibling of Design System")

        blocks = _get_blocks_for_page(final_state_backend, page.get("_id", ""))

        # Check for main heading
        if not _has_block_with_content(blocks, "Design System Audit", "heading1") and \
           not _has_block_with_content(blocks, "Audit Report", "heading1"):
            errors.append("[X] Missing heading_1 '🎨 Design System Audit Report'")
        else:
            checks_passed.append("[C] has heading_1 '🎨 Design System Audit Report'")

        # Check for System Architecture heading
        if not _has_block_with_content(blocks, "Architecture", "heading2") and \
           not _has_block_with_content(blocks, "System Architecture", "heading2"):
            errors.append("[X] Missing heading_2 '📂 System Architecture'")
        else:
            checks_passed.append("[C] has heading_2 '📂 System Architecture'")

        # Check for todo blocks (Quick Actions)
        todos = [b for b in blocks if b.get("type") == "todo"]
        if len(todos) < 3:
            errors.append(f"[X] Missing todo blocks for Quick Actions (found {len(todos)}/3)")
        else:
            checks_passed.append(f"[C] has todo blocks for Quick Actions (found {len(todos)}/3)")

        # Check for bookmark block
        if not _has_block_type(blocks, "bookmark"):
            errors.append("[X] Missing bookmark block")
        else:
            checks_passed.append("[C] has bookmark block")

        # Check for quote block
        if not _has_block_type(blocks, "quote"):
            errors.append("[X] Missing quote block")
        else:
            checks_passed.append("[C] has quote block")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: enhance-team-directory-structure-v2
# =============================================================================
def _validate_enhance_team_directory_structure(
    final_state_backend: Backend,
    final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate enhanced Team Directory structure."""
    errors: list[str] = []
    checks_passed: list[str] = []

    try:
        page = _find_page_by_title(final_state_backend, "Team Directory")
        if not page:
            errors.append("[X] Team Directory page not found")
        else:
            checks_passed.append("[C] Team Directory page found")

        blocks = _get_blocks_for_page(final_state_backend, page.get("_id", ""))

        # Check for Department Overview heading
        if not _has_block_with_content(blocks, "Department Overview", "heading2"):
            errors.append("[X] Missing heading_2 '🏢 Department Overview'")
        else:
            checks_passed.append("[C] has heading_2 '🏢 Department Overview'")

        # Check for Team Statistics heading
        if not _has_block_with_content(blocks, "Team Statistics", "heading2") and \
           not _has_block_with_content(blocks, "Statistics", "heading2"):
            errors.append("[X] Missing heading_2 '📊 Team Statistics'")
        else:
            checks_passed.append("[C] has heading_2 '📊 Team Statistics'")

        # Check for divider
        if not _has_block_type(blocks, "divider"):
            errors.append("[X] Missing divider block")
        else:
            checks_passed.append("[C] has divider block")

        # Check for statistics paragraph
        if not _has_block_with_content(blocks, "team members", "paragraph") and \
           not _has_block_with_content(blocks, "Total", "paragraph"):
            errors.append("[X] Missing statistics paragraph")
        else:
            checks_passed.append("[C] has statistics paragraph")

        # Check for blue callouts (converted from email bullets)
        blue_callouts = [b for b in blocks if b.get("type") == "callout" and
                        "blue" in b.get("properties", {}).get("backgroundColor", "").lower()]
        # Lenient - just check some callouts exist
        callouts = [b for b in blocks if b.get("type") == "callout"]
        if len(callouts) < 1:
            errors.append("[X] Missing callout blocks for email items")
        else:
            checks_passed.append("[C] has callout blocks for email items")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: prd-requirement-priorities-section-v2
# =============================================================================
def _validate_prd_requirement_priorities_section(
    final_state_backend: Backend,
    final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Requirement Priorities section in PRD."""
    errors: list[str] = []
    checks_passed: list[str] = []

    # Find the Comprehensive PRD page
    try:
        page = _find_page_by_title(final_state_backend, "Comprehensive Product Requirements Document")
        if not page:
            page = _find_page_by_title(final_state_backend, "Product Requirements")
        if not page:
            errors.append("[X] Comprehensive PRD page not found")
        else:
            checks_passed.append("[C] Comprehensive PRD page found")

        blocks = _get_blocks_for_page(final_state_backend, page.get("_id", ""))

        # Check for Requirement Priorities heading
        if not _has_block_with_content(blocks, "Requirement Priorities", "heading2") and \
           not _has_block_with_content(blocks, "Priorities", "heading2"):
            errors.append("[X] Missing heading_2 '📋 Requirement Priorities'")
        else:
            checks_passed.append("[C] has heading_2 '📋 Requirement Priorities'")

        # Check for 3 todos (one per Part)
        todos = [b for b in blocks if b.get("type") == "todo"]
        review_todos = [t for t in todos if "review" in t.get("content", "").lower() and
                       "part" in t.get("content", "").lower()]
        if len(review_todos) < 3:
            errors.append(f"[X] Missing review todos for each Part (found {len(review_todos)}/3)")
        else:
            checks_passed.append(f"[C] has review todos for each Part (found {len(review_todos)}/3)")

        # Check for divider
        if not _has_block_type(blocks, "divider"):
            errors.append("[X] Missing divider block")
        else:
            checks_passed.append("[C] has divider block")

        # Check for red callout with deadline
        has_red_callout = False
        for b in blocks:
            if b.get("type") == "callout":
                props = b.get("properties", {})
                bg = props.get("backgroundColor", "")
                content = b.get("content", "").lower()
                if "red" in bg.lower() and ("deadline" in content or "q1" in content):
                    has_red_callout = True
                    break

        if not has_red_callout:
            errors.append("[X] Missing red callout with deadline")
        else:
            checks_passed.append("[C] has red callout with deadline")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: project-guidelines-navigation-guide-v2
# =============================================================================
def _validate_project_guidelines_navigation_guide(
    final_state_backend: Backend,
    final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Quick Navigation Guide on Project Guidelines page."""
    errors: list[str] = []
    checks_passed: list[str] = []

    try:
        page = _find_page_by_title(final_state_backend, "Project Guidelines")
        if not page:
            errors.append("[X] Project Guidelines page not found")
        else:
            checks_passed.append("[C] Project Guidelines page found")

        blocks = _get_blocks_for_page(final_state_backend, page.get("_id", ""))

        # Check for Quick Navigation Guide heading
        if not _has_block_with_content(blocks, "Quick Navigation", "heading1") and \
           not _has_block_with_content(blocks, "Navigation Guide", "heading1"):
            errors.append("[X] Missing heading_1 '📋 Quick Navigation Guide'")
        else:
            checks_passed.append("[C] has heading_1 '📋 Quick Navigation Guide'")

        # Check for numbered list items (should have multiple for guideline groups)
        numbered_items = [b for b in blocks if b.get("type") == "numberedList"]
        if len(numbered_items) < 5:
            errors.append(f"[X] Missing numbered list items for guideline groups (found {len(numbered_items)})")
        else:
            checks_passed.append(f"[C] has numbered list items for guideline groups (found {len(numbered_items)})")

        # Check for Most Important Guidelines heading
        if not _has_block_with_content(blocks, "Most Important", "heading2") and \
           not _has_block_with_content(blocks, "Important Guidelines", "heading2"):
            errors.append("[X] Missing heading_2 '⚡ Most Important Guidelines'")
        else:
            checks_passed.append("[C] has heading_2 '⚡ Most Important Guidelines'")

        # Check for red callout
        has_red_callout = any(
            b.get("type") == "callout" and
            "red" in b.get("properties", {}).get("backgroundColor", "").lower()
            for b in blocks
        )
        if not has_red_callout:
            errors.append("[X] Missing red callout with critical guidelines")
        else:
            checks_passed.append("[C] has red callout with critical guidelines")

        # Check for dividers (at least 2)
        dividers = [b for b in blocks if b.get("type") == "divider"]
        if len(dividers) < 2:
            errors.append(f"[X] Missing dividers (found {len(dividers)}/2)")
        else:
            checks_passed.append(f"[C] has dividers (found {len(dividers)}/2)")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: add-react-examples-section-2-v2
# =============================================================================
def _validate_add_react_examples_section_2(
    final_state_backend: Backend,
    final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate React Examples section in Code Examples Repository."""
    errors: list[str] = []
    checks_passed: list[str] = []

    try:
        page = _find_page_by_title(final_state_backend, "Code Examples Repository")
        if not page:
            page = _find_page_by_title(final_state_backend, "Code Examples")
        if not page:
            errors.append("[X] Code Examples Repository page not found")
        else:
            checks_passed.append("[C] Code Examples Repository page found")

        blocks = _get_blocks_for_page(final_state_backend, page.get("_id", ""))

        # Check for React Examples heading
        if not _has_block_with_content(blocks, "React Examples", "heading2") and \
           not _has_block_with_content(blocks, "React", "heading2"):
            errors.append("[X] Missing heading_2 'React Examples'")
        else:
            checks_passed.append("[C] has heading_2 'React Examples'")

        # Check for code block with javascript/jsx
        code_blocks = [b for b in blocks if b.get("type") == "code"]
        has_react_code = any(
            "javascript" in b.get("properties", {}).get("language", "").lower() or
            "jsx" in b.get("properties", {}).get("language", "").lower() or
            "usestate" in b.get("content", "").lower() or
            "useeffect" in b.get("content", "").lower()
            for b in code_blocks
        )
        if not has_react_code:
            errors.append("[X] Missing JavaScript code block with React hooks")
        else:
            checks_passed.append("[C] has JavaScript code block with React hooks")

        # Check for paragraph about state management
        if not _has_block_with_content(blocks, "state management", "paragraph") and \
           not _has_block_with_content(blocks, "hooks pattern", "paragraph") and \
           not _has_block_with_content(blocks, "React", "paragraph"):
            errors.append("[X] Missing paragraph about React hooks/state management")
        else:
            checks_passed.append("[C] has paragraph about React hooks/state management")

        # Check for blue callout
        has_blue_callout = any(
            b.get("type") == "callout" and
            "blue" in b.get("properties", {}).get("backgroundColor", "").lower()
            for b in blocks
        )
        if not has_blue_callout:
            errors.append("[X] Missing blue callout with best practice")
        else:
            checks_passed.append("[C] has blue callout with best practice")

        # Check for divider
        if not _has_block_type(blocks, "divider"):
            errors.append("[X] Missing divider block")
        else:
            checks_passed.append("[C] has divider block")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: add-development-standards-section-v2
# =============================================================================
def _validate_add_development_standards_section(
    final_state_backend: Backend,
    final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Development Standards section in Project Guidelines."""
    errors: list[str] = []
    checks_passed: list[str] = []

    try:
        page = _find_page_by_title(final_state_backend, "Project Guidelines")
        if not page:
            errors.append("[X] Project Guidelines page not found")
        else:
            checks_passed.append("[C] Project Guidelines page found")

        blocks = _get_blocks_for_page(final_state_backend, page.get("_id", ""))

        # Check for Development Standards heading
        if not _has_block_with_content(blocks, "Development Standards", "heading2"):
            errors.append("[X] Missing heading_2 '🔧 Development Standards'")
        else:
            checks_passed.append("[C] has heading_2 '🔧 Development Standards'")

        # Check for 3 numbered list items
        numbered_items = [b for b in blocks if b.get("type") == "numberedList"]
        standards_items = [b for b in numbered_items if
                          "linting" in b.get("content", "").lower() or
                          "test coverage" in b.get("content", "").lower() or
                          "80%" in b.get("content", "") or
                          "pr" in b.get("content", "").lower() or
                          "jira" in b.get("content", "").lower()]
        if len(standards_items) < 3:
            errors.append(f"[X] Missing numbered list items for standards (found {len(standards_items)}/3)")
        else:
            checks_passed.append(f"[C] has numbered list items for standards (found {len(standards_items)}/3)")

        # Check for purple callout
        has_purple_callout = any(
            b.get("type") == "callout" and
            "purple" in b.get("properties", {}).get("backgroundColor", "").lower()
            for b in blocks
        )
        if not has_purple_callout:
            errors.append("[X] Missing purple callout with onboarding reminder")
        else:
            checks_passed.append("[C] has purple callout with onboarding reminder")

        # Check for count paragraph at end
        if not _has_block_with_content(blocks, "Total", "paragraph") and \
           not _has_block_with_content(blocks, "callout", "paragraph"):
            errors.append("[X] Missing paragraph with total callout count")
        else:
            checks_passed.append("[C] has paragraph with total callout count")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: code-repository-categorization-system-v2
# =============================================================================
def _validate_code_repository_categorization_system(
    final_state_backend: Backend,
    final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate categorization system in Code Examples Repository."""
    errors: list[str] = []
    checks_passed: list[str] = []

    try:
        page = _find_page_by_title(final_state_backend, "Code Examples Repository")
        if not page:
            page = _find_page_by_title(final_state_backend, "Code Examples")
        if not page:
            errors.append("[X] Code Examples Repository page not found")
        else:
            checks_passed.append("[C] Code Examples Repository page found")

        blocks = _get_blocks_for_page(final_state_backend, page.get("_id", ""))

        # Check for Repository Statistics heading
        if not _has_block_with_content(blocks, "Repository Statistics", "heading2") and \
           not _has_block_with_content(blocks, "Statistics", "heading2"):
            errors.append("[X] Missing heading_2 '📂 Repository Statistics'")
        else:
            checks_passed.append("[C] has heading_2 '📂 Repository Statistics'")

        # Check for gray callout with block count
        has_gray_callout = any(
            b.get("type") == "callout" and
            "gray" in b.get("properties", {}).get("backgroundColor", "").lower() and
            ("blocks" in b.get("content", "").lower() or "contains" in b.get("content", "").lower())
            for b in blocks
        )
        if not has_gray_callout:
            errors.append("[X] Missing gray callout with block count")
        else:
            checks_passed.append("[C] has gray callout with block count")

        # Check for Categories heading
        if not _has_block_with_content(blocks, "Categories", "heading2"):
            errors.append("[X] Missing heading_2 '🏷️ Categories'")
        else:
            checks_passed.append("[C] has heading_2 '🏷️ Categories'")

        # Check for 5 numbered list items (categories)
        numbered_items = [b for b in blocks if b.get("type") == "numberedList"]
        if len(numbered_items) < 5:
            errors.append(f"[X] Missing numbered list items for categories (found {len(numbered_items)}/5)")
        else:
            checks_passed.append(f"[C] has numbered list items for categories (found {len(numbered_items)}/5)")

        # Check for yellow callouts above code blocks
        yellow_callouts = [b for b in blocks if
                          b.get("type") == "callout" and
                          "yellow" in b.get("properties", {}).get("backgroundColor", "").lower()]
        if len(yellow_callouts) < 1:
            errors.append("[X] Missing yellow callouts with category assignments")
        else:
            checks_passed.append("[C] has yellow callouts with category assignments")

        # Check for divider
        if not _has_block_type(blocks, "divider"):
            errors.append("[X] Missing divider block")
        else:
            checks_passed.append("[C] has divider block")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: create-architecture-decision-records-2-v2
# =============================================================================
def _validate_create_architecture_decision_records_2(
    final_state_backend: Backend,
    final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Architecture Decision Records page creation."""
    errors: list[str] = []
    checks_passed: list[str] = []

    # Find the ADR page
    try:
        page = _find_page_by_title(final_state_backend, "Architecture Decision Records")
        if not page:
            page = _find_page_by_title(final_state_backend, "ADR")
        if not page:
            errors.append("[X] Architecture Decision Records page not found")
        else:
            checks_passed.append("[C] Architecture Decision Records page found")

        # Check it's under Architecture page
        architecture_page = _find_page_by_title(final_state_backend, "Architecture")
        if architecture_page and page.get("parentId") != architecture_page.get("_id"):
            # Lenient - just warn, don't fail
            pass

        blocks = _get_blocks_for_page(final_state_backend, page.get("_id", ""))

        # Check for main heading
        if not _has_block_with_content(blocks, "Architecture Decision Records", "heading1") and \
           not _has_block_with_content(blocks, "ADR", "heading1"):
            errors.append("[X] Missing heading_1 for Architecture Decision Records")
        else:
            checks_passed.append("[C] has heading_1 for Architecture Decision Records")

        # Check for blue callout
        has_blue_callout = any(
            b.get("type") == "callout" and
            "blue" in b.get("properties", {}).get("backgroundColor", "").lower()
            for b in blocks
        )
        if not has_blue_callout:
            errors.append("[X] Missing blue callout with description")
        else:
            checks_passed.append("[C] has blue callout with description")

        # Check for ADR Template heading
        if not _has_block_with_content(blocks, "ADR Template", "heading2") and \
           not _has_block_with_content(blocks, "Template", "heading2"):
            errors.append("[X] Missing heading_2 '🎯 ADR Template'")
        else:
            checks_passed.append("[C] has heading_2 '🎯 ADR Template'")

        # Check for markdown code block
        code_blocks = [b for b in blocks if b.get("type") == "code"]
        has_markdown = any("markdown" in b.get("properties", {}).get("language", "").lower()
                          for b in code_blocks)
        if not has_markdown and len(code_blocks) < 1:
            errors.append("[X] Missing markdown code block with ADR template")
        else:
            checks_passed.append("[C] has markdown code block with ADR template")

        # Check for 3 ADR example headings
        adr_headings = [b for b in blocks if
                       b.get("type") == "heading3" and
                       "adr" in b.get("content", "").lower()]
        if len(adr_headings) < 3:
            errors.append(f"[X] Missing ADR example headings (found {len(adr_headings)}/3)")
        else:
            checks_passed.append(f"[C] has ADR example headings (found {len(adr_headings)}/3)")

        # Check for bulleted lists with status/date/impact
        bullet_items = [b for b in blocks if b.get("type") == "bulletedList"]
        if len(bullet_items) < 3:
            errors.append("[X] Missing bulleted lists for ADR details")
        else:
            checks_passed.append("[C] has bulleted lists for ADR details")

        # Check for divider
        if not _has_block_type(blocks, "divider"):
            errors.append("[X] Missing divider block")
        else:
            checks_passed.append("[C] has divider block")

        # Check for summary paragraph
        if not _has_block_with_content(blocks, "Total ADRs", "paragraph") and \
           not _has_block_with_content(blocks, "documented", "paragraph"):
            errors.append("[X] Missing summary paragraph with ADR count")
        else:
            checks_passed.append("[C] has summary paragraph with ADR count")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: create-daily-standup-tracker-v2
# =============================================================================
def _validate_create_daily_standup_tracker(
    final_state_backend: Backend,
    final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Daily Standup Tracker page creation."""
    errors: list[str] = []
    checks_passed: list[str] = []

    # Find the tracker page
    try:
        page = _find_page_by_title(final_state_backend, "Daily Standup Tracker")
        if not page:
            page = _find_page_by_title(final_state_backend, "Standup Tracker")
        if not page:
            errors.append("[X] Daily Standup Tracker page not found")
        else:
            checks_passed.append("[C] Daily Standup Tracker page found")

        # Check it's under Meeting Notes
        meeting_notes = _find_page_by_title(final_state_backend, "Meeting Notes")
        if meeting_notes and page.get("parentId") != meeting_notes.get("_id"):
            # Lenient check
            pass

        blocks = _get_blocks_for_page(final_state_backend, page.get("_id", ""))

        # Check for main heading
        if not _has_block_with_content(blocks, "Daily Standup Tracker", "heading1") and \
           not _has_block_with_content(blocks, "Standup Tracker", "heading1"):
            errors.append("[X] Missing heading_1 '📅 Daily Standup Tracker'")
        else:
            checks_passed.append("[C] has heading_1 '📅 Daily Standup Tracker'")

        # Check for Week of heading
        if not _has_block_with_content(blocks, "Week of", "heading2"):
            errors.append("[X] Missing heading_2 '📆 Week of [date]'")
        else:
            checks_passed.append("[C] has heading_2 '📆 Week of [date]'")

        # Check for 5 weekday headings (Monday-Friday)
        weekdays = ["monday", "tuesday", "wednesday", "thursday", "friday"]
        found_days = 0
        for day in weekdays:
            if _has_block_with_content(blocks, day, "heading3"):
                found_days += 1

        if found_days < 5:
            errors.append(f"[X] Missing weekday heading_3 blocks (found {found_days}/5)")
        else:
            checks_passed.append(f"[C] has weekday heading_3 blocks (found {found_days}/5)")

        # Check for todos (3 per day = 15 total)
        todos = [b for b in blocks if b.get("type") == "todo"]
        if len(todos) < 15:
            errors.append(f"[X] Missing todo blocks (found {len(todos)}/15)")
        else:
            checks_passed.append(f"[C] has todo blocks (found {len(todos)}/15)")

        # Check for mid-week callout
        has_yellow_callout = any(
            b.get("type") == "callout" and
            "yellow" in b.get("properties", {}).get("backgroundColor", "").lower() and
            "mid-week" in b.get("content", "").lower()
            for b in blocks
        )
        if not has_yellow_callout:
            errors.append("[X] Missing yellow mid-week callout")
        else:
            checks_passed.append("[C] has yellow mid-week callout")

        # Check for Weekly Summary heading
        if not _has_block_with_content(blocks, "Weekly Summary", "heading2"):
            errors.append("[X] Missing heading_2 '📊 Weekly Summary'")
        else:
            checks_passed.append("[C] has heading_2 '📊 Weekly Summary'")

        # Check for summary paragraph
        if not _has_block_with_content(blocks, "Total standup tasks", "paragraph") and \
           not _has_block_with_content(blocks, "15", "paragraph"):
            errors.append("[X] Missing summary paragraph with task count")
        else:
            checks_passed.append("[C] has summary paragraph with task count")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: feature-requests-quarterly-planning-v2
# =============================================================================
def _validate_feature_requests_quarterly_planning(
    final_state_backend: Backend,
    final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Quarterly Planning Matrix on Feature Requests page."""
    errors: list[str] = []
    checks_passed: list[str] = []

    try:
        page = _find_page_by_title(final_state_backend, "Feature Requests")
        if not page:
            errors.append("[X] Feature Requests page not found")
        else:
            checks_passed.append("[C] Feature Requests page found")

        blocks = _get_blocks_for_page(final_state_backend, page.get("_id", ""))

        # Check for Quarterly Planning Matrix heading
        if not _has_block_with_content(blocks, "Planning Matrix", "heading2") and \
           not _has_block_with_content(blocks, "Q1 2024", "heading2"):
            errors.append("[X] Missing heading_2 '📐 Q1 2024 Planning Matrix'")
        else:
            checks_passed.append("[C] has heading_2 '📐 Q1 2024 Planning Matrix'")

        # Check for 3 effort category headings
        effort_keywords = ["quick wins", "medium effort", "major initiatives"]
        found_categories = 0
        for keyword in effort_keywords:
            if _has_block_with_content(blocks, keyword, "heading3"):
                found_categories += 1

        if found_categories < 3:
            errors.append(f"[X] Missing effort category headings (found {found_categories}/3)")
        else:
            checks_passed.append(f"[C] has effort category headings (found {found_categories}/3)")

        # Check for time estimate paragraphs
        has_time_estimates = any(
            b.get("type") == "paragraph" and
            ("week" in b.get("content", "").lower() or "month" in b.get("content", "").lower())
            for b in blocks
        )
        if not has_time_estimates:
            errors.append("[X] Missing time estimate paragraphs")
        else:
            checks_passed.append("[C] has time estimate paragraphs")

        # Check for yellow callout with planning session date
        has_yellow_callout = any(
            b.get("type") == "callout" and
            "yellow" in b.get("properties", {}).get("backgroundColor", "").lower() and
            "planning" in b.get("content", "").lower()
            for b in blocks
        )
        if not has_yellow_callout:
            errors.append("[X] Missing yellow callout with planning session date")
        else:
            checks_passed.append("[C] has yellow callout with planning session date")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: team-directory-comprehensive-update-v2
# =============================================================================
def _validate_team_directory_comprehensive_update(
    final_state_backend: Backend,
    final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate comprehensive update to Team Directory page."""
    errors: list[str] = []
    checks_passed: list[str] = []

    try:
        page = _find_page_by_title(final_state_backend, "Team Directory")
        if not page:
            errors.append("[X] Team Directory page not found")
        else:
            checks_passed.append("[C] Team Directory page found")

        blocks = _get_blocks_for_page(final_state_backend, page.get("_id", ""))

        # Check for Last Updated heading
        if not _has_block_with_content(blocks, "Last Updated", "heading2"):
            errors.append("[X] Missing heading_2 '🕒 Last Updated'")
        else:
            checks_passed.append("[C] has heading_2 '🕒 Last Updated'")

        # Check for Team Overview heading
        if not _has_block_with_content(blocks, "Team Overview", "heading2"):
            errors.append("[X] Missing heading_2 '📊 Team Overview'")
        else:
            checks_passed.append("[C] has heading_2 '📊 Team Overview'")

        # Check for gray callout with quick stats
        has_gray_callout = any(
            b.get("type") == "callout" and
            "gray" in b.get("properties", {}).get("backgroundColor", "").lower() and
            ("departments" in b.get("content", "").lower() or "team members" in b.get("content", "").lower())
            for b in blocks
        )
        if not has_gray_callout:
            errors.append("[X] Missing gray callout with team statistics")
        else:
            checks_passed.append("[C] has gray callout with team statistics")

        # Check for Quick Links heading
        if not _has_block_with_content(blocks, "Quick Links", "heading2"):
            errors.append("[X] Missing heading_2 '🔗 Quick Links'")
        else:
            checks_passed.append("[C] has heading_2 '🔗 Quick Links'")

        # Check for bookmark blocks
        bookmarks = [b for b in blocks if b.get("type") == "bookmark"]
        if len(bookmarks) < 2:
            errors.append(f"[X] Missing bookmark blocks (found {len(bookmarks)}/2)")
        else:
            checks_passed.append(f"[C] has bookmark blocks (found {len(bookmarks)}/2)")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: prd-table-of-contents-v2
# =============================================================================
def _validate_prd_table_of_contents(
    final_state_backend: Backend,
    final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Table of Contents in Product Requirements Document."""
    errors: list[str] = []
    checks_passed: list[str] = []

    try:
        page = _find_page_by_title(final_state_backend, "Product Requirements Document")
        if not page:
            page = _find_page_by_title(final_state_backend, "PRD")
        if not page:
            errors.append("[X] Product Requirements Document page not found")
        else:
            checks_passed.append("[C] Product Requirements Document page found")

        blocks = _get_blocks_for_page(final_state_backend, page.get("_id", ""))

        # Check for Table of Contents heading
        if not _has_block_with_content(blocks, "Table of Contents", "heading2"):
            errors.append("[X] Missing heading_2 '📑 Table of Contents'")
        else:
            checks_passed.append("[C] has heading_2 '📑 Table of Contents'")

        # Check for numbered list items
        numbered_items = [b for b in blocks if b.get("type") == "numberedList"]
        if len(numbered_items) < 3:
            errors.append(f"[X] Missing numbered list items for TOC (found {len(numbered_items)})")
        else:
            checks_passed.append(f"[C] has numbered list items for TOC (found {len(numbered_items)})")

        # Check for divider
        if not _has_block_type(blocks, "divider"):
            errors.append("[X] Missing divider block")
        else:
            checks_passed.append("[C] has divider block")

        # Check for gray callout with navigation tip
        has_gray_callout = any(
            b.get("type") == "callout" and
            "gray" in b.get("properties", {}).get("backgroundColor", "").lower() and
            ("navigation" in b.get("content", "").lower() or "ctrl+f" in b.get("content", "").lower())
            for b in blocks
        )
        if not has_gray_callout:
            errors.append("[X] Missing gray callout with navigation tip")
        else:
            checks_passed.append("[C] has gray callout with navigation tip")

        # Check for Document History heading
        if not _has_block_with_content(blocks, "Document History", "heading2"):
            errors.append("[X] Missing heading_2 '📝 Document History'")
        else:
            checks_passed.append("[C] has heading_2 '📝 Document History'")

        # Check for todo block
        todos = [b for b in blocks if b.get("type") == "todo"]
        if len(todos) < 1:
            errors.append("[X] Missing todo block for quarterly review")
        else:
            checks_passed.append("[C] has todo block for quarterly review")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: weekly-standup-template-modification-v2
# =============================================================================
def _validate_weekly_standup_template_modification(
    final_state_backend: Backend,
    final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate modifications to Weekly Standup Template."""
    errors: list[str] = []
    checks_passed: list[str] = []

    try:
        page = _find_page_by_title(final_state_backend, "Weekly Standup Template")
        if not page:
            errors.append("[X] Weekly Standup Template page not found")
        else:
            checks_passed.append("[C] Weekly Standup Template page found")

        blocks = _get_blocks_for_page(final_state_backend, page.get("_id", ""))

        # Check for Team Velocity Metrics heading
        if not _has_block_with_content(blocks, "Team Velocity Metrics", "heading2") and \
           not _has_block_with_content(blocks, "Velocity Metrics", "heading2"):
            errors.append("[X] Missing heading_2 'Team Velocity Metrics'")
        else:
            checks_passed.append("[C] has heading_2 'Team Velocity Metrics'")

        # Check for quote block
        if not _has_block_type(blocks, "quote"):
            errors.append("[X] Missing quote block")
        else:
            checks_passed.append("[C] has quote block")

        # Check for 4 numbered list items with TBD placeholders
        numbered_items = [b for b in blocks if b.get("type") == "numberedList"]
        tbd_items = [b for b in numbered_items if "tbd" in b.get("content", "").lower()]
        if len(tbd_items) < 4:
            errors.append(f"[X] Missing numbered list items with TBD placeholders (found {len(tbd_items)}/4)")
        else:
            checks_passed.append(f"[C] has numbered list items with TBD placeholders (found {len(tbd_items)}/4)")

        # Check that todos have TEMPLATE prefix
        todos = [b for b in blocks if b.get("type") == "todo"]
        template_todos = [t for t in todos if "template:" in t.get("content", "").lower()]
        # Lenient - check at least some todos have the prefix
        if len(todos) > 0 and len(template_todos) < 1:
            errors.append("[X] Todos should have 'TEMPLATE: ' prefix")
        else:
            checks_passed.append("[C] Todos should have 'TEMPLATE: ' prefix")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: add-utility-functions-section-v2
# =============================================================================
def _validate_add_utility_functions_section(
    final_state_backend: Backend,
    final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Utility Functions section in Code Examples Repository."""
    errors: list[str] = []
    checks_passed: list[str] = []

    try:
        page = _find_page_by_title(final_state_backend, "Code Examples Repository")
        if not page:
            page = _find_page_by_title(final_state_backend, "Code Examples")
        if not page:
            errors.append("[X] Code Examples Repository page not found")
        else:
            checks_passed.append("[C] Code Examples Repository page found")

        blocks = _get_blocks_for_page(final_state_backend, page.get("_id", ""))

        # Check for Utility Functions heading
        if not _has_block_with_content(blocks, "Utility Functions", "heading2"):
            errors.append("[X] Missing heading_2 '🔧 Utility Functions'")
        else:
            checks_passed.append("[C] has heading_2 '🔧 Utility Functions'")

        # Check for JavaScript code block with debounce
        code_blocks = [b for b in blocks if b.get("type") == "code"]
        has_debounce = any(
            "debounce" in b.get("content", "").lower() and
            "javascript" in b.get("properties", {}).get("language", "").lower()
            for b in code_blocks
        )
        if not has_debounce:
            errors.append("[X] Missing JavaScript code block with debounce function")
        else:
            checks_passed.append("[C] has JavaScript code block with debounce function")

        # Check for usage paragraph
        if not _has_block_with_content(blocks, "Usage", "paragraph") and \
           not _has_block_with_content(blocks, "Prevents", "paragraph"):
            errors.append("[X] Missing usage paragraph")
        else:
            checks_passed.append("[C] has usage paragraph")

        # Check for TypeScript code block with interface
        has_typescript = any(
            "typescript" in b.get("properties", {}).get("language", "").lower() and
            "interface" in b.get("content", "").lower()
            for b in code_blocks
        )
        if not has_typescript:
            errors.append("[X] Missing TypeScript code block with User interface")
        else:
            checks_passed.append("[C] has TypeScript code block with User interface")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: prd-overview-statistics-v2
# =============================================================================
def _validate_prd_overview_statistics(
    final_state_backend: Backend,
    final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Overview Statistics in PRD."""
    errors: list[str] = []
    checks_passed: list[str] = []

    try:
        page = _find_page_by_title(final_state_backend, "Product Requirements Document")
        if not page:
            page = _find_page_by_title(final_state_backend, "Comprehensive Product Requirements")
        if not page:
            errors.append("[X] Product Requirements Document page not found")
        else:
            checks_passed.append("[C] Product Requirements Document page found")

        blocks = _get_blocks_for_page(final_state_backend, page.get("_id", ""))

        # Check for gray callout with review status
        has_gray_callout = any(
            b.get("type") == "callout" and
            "gray" in b.get("properties", {}).get("backgroundColor", "").lower() and
            ("review" in b.get("content", "").lower() or "pending" in b.get("content", "").lower())
            for b in blocks
        )
        if not has_gray_callout:
            errors.append("[X] Missing gray callout with review status")
        else:
            checks_passed.append("[C] has gray callout with review status")

        # Check for Overview Statistics heading
        if not _has_block_with_content(blocks, "Overview Statistics", "heading3") and \
           not _has_block_with_content(blocks, "Statistics", "heading3"):
            errors.append("[X] Missing heading_3 '📊 Overview Statistics'")
        else:
            checks_passed.append("[C] has heading_3 '📊 Overview Statistics'")

        # Check for numbered list with statistics
        numbered_items = [b for b in blocks if b.get("type") == "numberedList"]
        stats_items = [b for b in numbered_items if
                      "subsection" in b.get("content", "").lower() or
                      "key points" in b.get("content", "").lower() or
                      "total" in b.get("content", "").lower()]
        if len(stats_items) < 2:
            errors.append(f"[X] Missing numbered list with statistics (found {len(stats_items)})")
        else:
            checks_passed.append(f"[C] has numbered list with statistics (found {len(stats_items)})")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: company-handbook-comprehensive-update-v2
# =============================================================================
def _validate_company_handbook_comprehensive_update(
    final_state_backend: Backend,
    final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate comprehensive update to Company Handbook."""
    errors: list[str] = []
    checks_passed: list[str] = []

    try:
        page = _find_page_by_title(final_state_backend, "Company Handbook")
        if not page:
            errors.append("[X] Company Handbook page not found")
        else:
            checks_passed.append("[C] Company Handbook page found")

        blocks = _get_blocks_for_page(final_state_backend, page.get("_id", ""))

        # Check for Innovation value in bulleted list
        has_innovation = any(
            b.get("type") == "bulletedList" and
            "innovation" in b.get("content", "").lower()
            for b in blocks
        )
        if not has_innovation:
            errors.append("[X] Missing 'Innovation' bulleted list item in Our Values")
        else:
            checks_passed.append("[C] has 'Innovation' bulleted list item in Our Values")

        # Check for updated 401k text (6%)
        has_updated_401k = any(
            "6%" in b.get("content", "") and
            ("401" in b.get("content", "").lower() or "matching" in b.get("content", "").lower())
            for b in blocks
        )
        if not has_updated_401k:
            errors.append("[X] 401k not updated to 6%")
        else:
            checks_passed.append("[C] 401k updated to 6%")

        # Check for Code of Conduct heading
        if not _has_block_with_content(blocks, "Code of Conduct", "heading2"):
            errors.append("[X] Missing heading_2 'Code of Conduct'")
        else:
            checks_passed.append("[C] has heading_2 'Code of Conduct'")

        # Check for blue callout with 🤝
        has_blue_callout = any(
            b.get("type") == "callout" and
            "blue" in b.get("properties", {}).get("backgroundColor", "").lower() and
            ("respectful" in b.get("content", "").lower() or "inclusive" in b.get("content", "").lower())
            for b in blocks
        )
        if not has_blue_callout:
            errors.append("[X] Missing blue callout with inclusive workplace message")
        else:
            checks_passed.append("[C] has blue callout with inclusive workplace message")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: onboarding-guide-modifications-v2
# =============================================================================
def _validate_onboarding_guide_modifications(
    final_state_backend: Backend,
    final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate modifications to Onboarding Guide."""
    errors: list[str] = []
    checks_passed: list[str] = []

    try:
        page = _find_page_by_title(final_state_backend, "Onboarding Guide")
        if not page:
            errors.append("[X] Onboarding Guide page not found")
        else:
            checks_passed.append("[C] Onboarding Guide page found")

        blocks = _get_blocks_for_page(final_state_backend, page.get("_id", ""))

        # Check for divider
        if not _has_block_type(blocks, "divider"):
            errors.append("[X] Missing divider block")
        else:
            checks_passed.append("[C] has divider block")

        # Check for blue callout with checkpoint
        has_blue_callout = any(
            b.get("type") == "callout" and
            "blue" in b.get("properties", {}).get("backgroundColor", "").lower() and
            "checkpoint" in b.get("content", "").lower()
            for b in blocks
        )
        if not has_blue_callout:
            errors.append("[X] Missing blue callout with checkpoint message")
        else:
            checks_passed.append("[C] has blue callout with checkpoint message")

        # Check for new numbered items (1:1 meetings, documentation, dev environment)
        numbered_items = [b for b in blocks if b.get("type") == "numberedList"]
        new_items = [b for b in numbered_items if
                    "1:1" in b.get("content", "") or
                    "documentation" in b.get("content", "").lower() or
                    "development environment" in b.get("content", "").lower()]
        if len(new_items) < 2:
            errors.append(f"[X] Missing new numbered items for First Week Goals (found {len(new_items)})")
        else:
            checks_passed.append(f"[C] has new numbered items for First Week Goals (found {len(new_items)})")

        # Check for todo at end with email summary
        todos = [b for b in blocks if b.get("type") == "todo"]
        has_summary_todo = any(
            "summary" in t.get("content", "").lower() or
            "manager" in t.get("content", "").lower()
            for t in todos
        )
        if not has_summary_todo:
            errors.append("[X] Missing todo for sending week 1 summary to manager")
        else:
            checks_passed.append("[C] has todo for sending week 1 summary to manager")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: create-project-guidelines-audit-v2
# =============================================================================
def _validate_create_project_guidelines_audit(
    final_state_backend: Backend,
    final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Project Guidelines Audit page creation."""
    errors: list[str] = []
    checks_passed: list[str] = []

    # Find the audit page
    try:
        page = _find_page_by_title(final_state_backend, "Project Guidelines Audit")
        if not page:
            page = _find_page_by_title(final_state_backend, "Guidelines Audit")
        if not page:
            errors.append("[X] Project Guidelines Audit page not found")
        else:
            checks_passed.append("[C] Project Guidelines Audit page found")

        # Check it's under Project Guidelines & Best Practices
        parent_page = _find_page_by_title(final_state_backend, "Project Guidelines")
        if parent_page:
            if page.get("parentId") != parent_page.get("_id"):
                errors.append("[X] Project Guidelines Audit is not a child of Project Guidelines & Best Practices")
            else:
                checks_passed.append("[C] Project Guidelines Audit is a child of Project Guidelines & Best Practices")

        blocks = _get_blocks_for_page(final_state_backend, page.get("_id", ""))

        # Check for main heading
        if not _has_block_with_content(blocks, "Guidelines Audit Report", "heading1") and \
           not _has_block_with_content(blocks, "Audit Report", "heading1"):
            errors.append("[X] Missing heading_1 '📋 Guidelines Audit Report'")
        else:
            checks_passed.append("[C] has heading_1 '📋 Guidelines Audit Report'")

        # Check for Callout Distribution heading
        if not _has_block_with_content(blocks, "Callout Distribution", "heading2") and \
           not _has_block_with_content(blocks, "Distribution", "heading2"):
            errors.append("[X] Missing heading_2 '🎨 Callout Distribution by Type'")
        else:
            checks_passed.append("[C] has heading_2 '🎨 Callout Distribution by Type'")

        # Check for numbered list with color counts
        numbered_items = [b for b in blocks if b.get("type") == "numberedList"]
        color_items = [b for b in numbered_items if "background" in b.get("content", "").lower()]
        if len(color_items) < 1:
            errors.append("[X] Missing numbered list with color distribution")
        else:
            checks_passed.append("[C] has numbered list with color distribution")

        # Check for Icon Usage heading
        if not _has_block_with_content(blocks, "Icon Usage", "heading2"):
            errors.append("[X] Missing heading_2 '📊 Icon Usage Statistics'")
        else:
            checks_passed.append("[C] has heading_2 '📊 Icon Usage Statistics'")

        # Check for Critical Guidelines heading
        if not _has_block_with_content(blocks, "Critical Guidelines", "heading2"):
            errors.append("[X] Missing heading_2 '⚠️ Critical Guidelines'")
        else:
            checks_passed.append("[C] has heading_2 '⚠️ Critical Guidelines'")

        # Check for Best Practices heading
        if not _has_block_with_content(blocks, "Best Practices", "heading2"):
            errors.append("[X] Missing heading_2 '💡 Best Practices'")
        else:
            checks_passed.append("[C] has heading_2 '💡 Best Practices'")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: engineering-wiki-troubleshooting-v2
# =============================================================================
def _validate_engineering_wiki_troubleshooting(
    final_state_backend: Backend,
    final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Troubleshooting section in Engineering Wiki."""
    errors: list[str] = []
    checks_passed: list[str] = []

    try:
        page = _find_page_by_title(final_state_backend, "Engineering Wiki")
        if not page:
            errors.append("[X] Engineering Wiki page not found")
        else:
            checks_passed.append("[C] Engineering Wiki page found")

        blocks = _get_blocks_for_page(final_state_backend, page.get("_id", ""))

        # Check for Troubleshooting heading
        if not _has_block_with_content(blocks, "Troubleshooting", "heading3"):
            errors.append("[X] Missing heading_3 '🔧 Troubleshooting Common Issues'")
        else:
            checks_passed.append("[C] has heading_3 '🔧 Troubleshooting Common Issues'")

        # Check for red callout
        has_red_callout = any(
            b.get("type") == "callout" and
            "red" in b.get("properties", {}).get("backgroundColor", "").lower()
            for b in blocks
        )
        if not has_red_callout:
            errors.append("[X] Missing red callout with error warning")
        else:
            checks_passed.append("[C] has red callout with error warning")

        # Check for 3 troubleshooting bullet items
        bullet_items = [b for b in blocks if b.get("type") == "bulletedList"]
        troubleshooting_items = [b for b in bullet_items if
                               "port" in b.get("content", "").lower() or
                               "module" in b.get("content", "").lower() or
                               "authentication" in b.get("content", "").lower()]
        if len(troubleshooting_items) < 3:
            errors.append(f"[X] Missing troubleshooting bullet items (found {len(troubleshooting_items)}/3)")
        else:
            checks_passed.append(f"[C] has troubleshooting bullet items (found {len(troubleshooting_items)}/3)")

        # Check for bookmark block
        if not _has_block_type(blocks, "bookmark"):
            errors.append("[X] Missing bookmark block for NPM documentation")
        else:
            checks_passed.append("[C] has bookmark block for NPM documentation")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: create-team-task-tracker-v2
# =============================================================================
def _validate_create_team_task_tracker(
    final_state_backend: Backend,
    final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Team Task Tracker page creation."""
    errors: list[str] = []
    checks_passed: list[str] = []

    # Find the tracker page
    try:
        page = _find_page_by_title(final_state_backend, "Team Task Tracker")
        if not page:
            page = _find_page_by_title(final_state_backend, "Task Tracker")
        if not page:
            errors.append("[X] Team Task Tracker page not found")
        else:
            checks_passed.append("[C] Team Task Tracker page found")

        # Check it's under Bug Tracker
        bug_tracker = _find_page_by_title(final_state_backend, "Bug Tracker")
        if bug_tracker:
            if page.get("parentId") != bug_tracker.get("_id"):
                errors.append("[X] Team Task Tracker is not a child of Bug Tracker")
            else:
                checks_passed.append("[C] Team Task Tracker is a child of Bug Tracker")

        blocks = _get_blocks_for_page(final_state_backend, page.get("_id", ""))

        # Check for main heading
        if not _has_block_with_content(blocks, "Team Task Tracker", "heading1"):
            errors.append("[X] Missing heading_1 '🎯 Team Task Tracker'")
        else:
            checks_passed.append("[C] has heading_1 '🎯 Team Task Tracker'")

        # Check for Bug Distribution Summary heading
        if not _has_block_with_content(blocks, "Bug Distribution", "heading2") and \
           not _has_block_with_content(blocks, "Distribution Summary", "heading2"):
            errors.append("[X] Missing heading_2 '📊 Bug Distribution Summary'")
        else:
            checks_passed.append("[C] has heading_2 '📊 Bug Distribution Summary'")

        # Check for blue callout with bug counts
        has_blue_callout = any(
            b.get("type") == "callout" and
            "blue" in b.get("properties", {}).get("backgroundColor", "").lower() and
            ("critical" in b.get("content", "").lower() or "medium" in b.get("content", "").lower())
            for b in blocks
        )
        if not has_blue_callout:
            errors.append("[X] Missing blue callout with bug distribution")
        else:
            checks_passed.append("[C] has blue callout with bug distribution")

        # Check for Urgent Items heading
        if not _has_block_with_content(blocks, "Urgent Items", "heading2"):
            errors.append("[X] Missing heading_2 '🚨 Urgent Items'")
        else:
            checks_passed.append("[C] has heading_2 '🚨 Urgent Items'")

        # Check for Task Assignments heading
        if not _has_block_with_content(blocks, "Task Assignments", "heading2"):
            errors.append("[X] Missing heading_2 '📋 Task Assignments'")
        else:
            checks_passed.append("[C] has heading_2 '📋 Task Assignments'")

        # Check for Last Sync heading
        if not _has_block_with_content(blocks, "Last Sync", "heading3"):
            errors.append("[X] Missing heading_3 '🔄 Last Sync'")
        else:
            checks_passed.append("[C] has heading_3 '🔄 Last Sync'")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: sprint-planning-reorganization-v2
# =============================================================================
def _validate_sprint_planning_reorganization(
    final_state_backend: Backend,
    final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Sprint Planning page reorganization."""
    errors: list[str] = []
    checks_passed: list[str] = []

    try:
        page = _find_page_by_title(final_state_backend, "Sprint Planning - Jan 15")
        if not page:
            page = _find_page_by_title(final_state_backend, "Sprint Planning")
        if not page:
            errors.append("[X] Sprint Planning page not found")
        else:
            checks_passed.append("[C] Sprint Planning page found")

        blocks = _get_blocks_for_page(final_state_backend, page.get("_id", ""))
        blocks_sorted = sorted(blocks, key=lambda b: b.get("order", 0))

        # Check that Attendees and Sprint Goals both exist
        has_attendees = _has_block_with_content(blocks, "Attendees", "heading2")
        has_sprint_goals = _has_block_with_content(blocks, "Sprint Goals", "heading2")

        if not has_attendees:
            errors.append("[X] Missing Attendees heading")
        else:
            checks_passed.append("[C] has Attendees heading")
        if not has_sprint_goals:
            errors.append("[X] Missing Sprint Goals heading")
        else:
            checks_passed.append("[C] has Sprint Goals heading")

        # Check for blue callout in Action Items
        has_blue_callout = any(
            b.get("type") == "callout" and
            "blue" in b.get("properties", {}).get("backgroundColor", "").lower() and
            "priority" in b.get("content", "").lower()
            for b in blocks
        )
        if not has_blue_callout:
            errors.append("[X] Missing blue callout with priority message in Action Items")
        else:
            checks_passed.append("[C] has blue callout with priority message in Action Items")

        # Check for Carol's todo
        todos = [b for b in blocks if b.get("type") == "todo"]
        has_carol_todo = any(
            "carol" in t.get("content", "").lower() and
            "design system" in t.get("content", "").lower()
            for t in todos
        )
        if not has_carol_todo:
            errors.append("[X] Missing Carol's todo for design system documentation")
        else:
            checks_passed.append("[C] has Carol's todo for design system documentation")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: company-handbook-cross-referencing-v2
# =============================================================================
def _validate_company_handbook_cross_referencing(
    final_state_backend: Backend,
    final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate cross-referencing system in Company Handbook."""
    errors: list[str] = []
    checks_passed: list[str] = []

    try:
        page = _find_page_by_title(final_state_backend, "Company Handbook")
        if not page:
            errors.append("[X] Company Handbook page not found")
        else:
            checks_passed.append("[C] Company Handbook page found")

        blocks = _get_blocks_for_page(final_state_backend, page.get("_id", ""))

        # Check for Quick Links heading
        if not _has_block_with_content(blocks, "Quick Links", "heading2") and \
           not _has_block_with_content(blocks, "Public Resources", "heading2"):
            errors.append("[X] Missing heading_2 '🔗 Quick Links to Public Resources'")
        else:
            checks_passed.append("[C] has heading_2 '🔗 Quick Links to Public Resources'")

        # Check for paragraph with resource count
        if not _has_block_with_content(blocks, "resources", "paragraph") and \
           not _has_block_with_content(blocks, "publicly accessible", "paragraph"):
            errors.append("[X] Missing paragraph with published page count")
        else:
            checks_passed.append("[C] has paragraph with published page count")

        # Check for Related Internal Documentation heading
        if not _has_block_with_content(blocks, "Related Internal", "heading2") and \
           not _has_block_with_content(blocks, "Internal Documentation", "heading2"):
            errors.append("[X] Missing heading_2 '📚 Related Internal Documentation'")
        else:
            checks_passed.append("[C] has heading_2 '📚 Related Internal Documentation'")

        # Check for 3 bookmark blocks
        bookmarks = [b for b in blocks if b.get("type") == "bookmark"]
        if len(bookmarks) < 3:
            errors.append(f"[X] Missing bookmark blocks (found {len(bookmarks)}/3)")
        else:
            checks_passed.append(f"[C] has bookmark blocks (found {len(bookmarks)}/3)")

        # Check for red security callout
        has_red_callout = any(
            b.get("type") == "callout" and
            "red" in b.get("properties", {}).get("backgroundColor", "").lower() and
            ("security" in b.get("content", "").lower() or "authentication" in b.get("content", "").lower())
            for b in blocks
        )
        if not has_red_callout:
            errors.append("[X] Missing red callout with security notice")
        else:
            checks_passed.append("[C] has red callout with security notice")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: engineering-wiki-development-workflow-v2
# =============================================================================
def _validate_engineering_wiki_development_workflow(
    final_state_backend: Backend,
    final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Development Workflow section in Engineering Wiki."""
    errors: list[str] = []
    checks_passed: list[str] = []

    try:
        page = _find_page_by_title(final_state_backend, "Engineering Wiki")
        if not page:
            errors.append("[X] Engineering Wiki page not found")
        else:
            checks_passed.append("[C] Engineering Wiki page found")

        blocks = _get_blocks_for_page(final_state_backend, page.get("_id", ""))

        # Check for Development Workflow heading
        if not _has_block_with_content(blocks, "Development Workflow", "heading2"):
            errors.append("[X] Missing heading_2 '🔄 Development Workflow'")
        else:
            checks_passed.append("[C] has heading_2 '🔄 Development Workflow'")

        # Check for orange callout
        has_orange_callout = any(
            b.get("type") == "callout" and
            "orange" in b.get("properties", {}).get("backgroundColor", "").lower()
            for b in blocks
        )
        if not has_orange_callout:
            errors.append("[X] Missing orange callout with workflow instructions")
        else:
            checks_passed.append("[C] has orange callout with workflow instructions")

        # Check for 7 numbered list items (workflow steps)
        numbered_items = [b for b in blocks if b.get("type") == "numberedList"]
        workflow_items = [b for b in numbered_items if
                         "branch" in b.get("content", "").lower() or
                         "test" in b.get("content", "").lower() or
                         "implement" in b.get("content", "").lower() or
                         "linter" in b.get("content", "").lower() or
                         "pull request" in b.get("content", "").lower() or
                         "review" in b.get("content", "").lower() or
                         "merge" in b.get("content", "").lower()]
        if len(workflow_items) < 5:  # Lenient - at least 5 of 7 steps
            errors.append(f"[X] Missing workflow steps in numbered list (found {len(workflow_items)})")
        else:
            checks_passed.append(f"[C] has workflow steps in numbered list (found {len(workflow_items)})")

        # Check for bash code block with git commands
        code_blocks = [b for b in blocks if b.get("type") == "code"]
        has_git_code = any(
            "bash" in b.get("properties", {}).get("language", "").lower() and
            "git" in b.get("content", "").lower()
            for b in code_blocks
        )
        if not has_git_code:
            errors.append("[X] Missing bash code block with git commands")
        else:
            checks_passed.append("[C] has bash code block with git commands")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: product-specifications-guidelines-v2
# =============================================================================
def _validate_product_specifications_guidelines(
    final_state_backend: Backend,
    final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Specification Guidelines in Product Specifications."""
    errors: list[str] = []
    checks_passed: list[str] = []

    try:
        page = _find_page_by_title(final_state_backend, "Product Specifications")
        if not page:
            page = _find_page_by_title(final_state_backend, "Product Specs")
        if not page:
            errors.append("[X] Product Specifications page not found")
        else:
            checks_passed.append("[C] Product Specifications page found")

        blocks = _get_blocks_for_page(final_state_backend, page.get("_id", ""))

        # Check for Specification Guidelines heading
        if not _has_block_with_content(blocks, "Specification Guidelines", "heading2"):
            errors.append("[X] Missing heading_2 '🔍 Specification Guidelines'")
        else:
            checks_passed.append("[C] has heading_2 '🔍 Specification Guidelines'")

        # Check for 4 numbered list items
        numbered_items = [b for b in blocks if b.get("type") == "numberedList"]
        guideline_items = [b for b in numbered_items if
                          "user story" in b.get("content", "").lower() or
                          "acceptance criteria" in b.get("content", "").lower() or
                          "success metrics" in b.get("content", "").lower() or
                          "stakeholder" in b.get("content", "").lower()]
        if len(guideline_items) < 4:
            errors.append(f"[X] Missing numbered list items for guidelines (found {len(guideline_items)}/4)")
        else:
            checks_passed.append(f"[C] has numbered list items for guidelines (found {len(guideline_items)}/4)")

        # Check for yellow callout with INVEST criteria
        has_yellow_callout = any(
            b.get("type") == "callout" and
            "yellow" in b.get("properties", {}).get("backgroundColor", "").lower() and
            "invest" in b.get("content", "").lower()
            for b in blocks
        )
        if not has_yellow_callout:
            errors.append("[X] Missing yellow callout with INVEST criteria")
        else:
            checks_passed.append("[C] has yellow callout with INVEST criteria")

        # Check that quote block still exists
        if not _has_block_type(blocks, "quote"):
            errors.append("[X] Original quote block is missing")
        else:
            checks_passed.append("[C] Original quote block is has")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: create-development-roadmap-v2
# =============================================================================
def _validate_create_development_roadmap(
    final_state_backend: Backend,
    final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Development Roadmap page creation."""
    errors: list[str] = []
    checks_passed: list[str] = []

    # Find the roadmap page
    try:
        page = _find_page_by_title(final_state_backend, "Development Roadmap")
        if not page:
            errors.append("[X] Development Roadmap page not found")
        else:
            checks_passed.append("[C] Development Roadmap page found")

        # Check sibling relationship with Project Roadmap
        project_roadmap = _find_page_by_title(final_state_backend, "Project Roadmap")
        if project_roadmap:
            if page.get("parentId") != project_roadmap.get("parentId"):
                errors.append("[X] Development Roadmap is not a sibling of Project Roadmap")
            else:
                checks_passed.append("[C] Development Roadmap is a sibling of Project Roadmap")

        blocks = _get_blocks_for_page(final_state_backend, page.get("_id", ""))

        # Check for main heading
        if not _has_block_with_content(blocks, "Development Roadmap", "heading1"):
            errors.append("[X] Missing heading_1 '🗺️ Development Roadmap'")
        else:
            checks_passed.append("[C] has heading_1 '🗺️ Development Roadmap'")

        # Check for Budget Allocation heading
        if not _has_block_with_content(blocks, "Budget Allocation", "heading2"):
            errors.append("[X] Missing heading_2 '💰 Budget Allocation'")
        else:
            checks_passed.append("[C] has heading_2 '💰 Budget Allocation'")

        # Check for yellow callout with learning budget
        has_yellow_callout = any(
            b.get("type") == "callout" and
            "yellow" in b.get("properties", {}).get("backgroundColor", "").lower() and
            ("budget" in b.get("content", "").lower() or "$" in b.get("content", ""))
            for b in blocks
        )
        if not has_yellow_callout:
            errors.append("[X] Missing yellow callout with learning budget")
        else:
            checks_passed.append("[C] has yellow callout with learning budget")

        # Check for Technology Focus Areas heading
        if not _has_block_with_content(blocks, "Technology Focus", "heading2"):
            errors.append("[X] Missing heading_2 '🛠️ Technology Focus Areas'")
        else:
            checks_passed.append("[C] has heading_2 '🛠️ Technology Focus Areas'")

        # Check for numbered list with tech items and quarters
        numbered_items = [b for b in blocks if b.get("type") == "numberedList"]
        tech_items = [b for b in numbered_items if
                     "q1" in b.get("content", "").lower() or
                     "q2" in b.get("content", "").lower() or
                     "q3" in b.get("content", "").lower() or
                     "q4" in b.get("content", "").lower() or
                     "quarter" in b.get("content", "").lower()]
        if len(tech_items) < 1:
            errors.append("[X] Missing numbered list with technology items and quarters")
        else:
            checks_passed.append("[C] has numbered list with technology items and quarters")

        # Check for Learning Resources heading
        if not _has_block_with_content(blocks, "Learning Resources", "heading2"):
            errors.append("[X] Missing heading_2 '📚 Learning Resources'")
        else:
            checks_passed.append("[C] has heading_2 '📚 Learning Resources'")

        # Check for bookmark block
        if not _has_block_type(blocks, "bookmark"):
            errors.append("[X] Missing bookmark block to engineering wiki")
        else:
            checks_passed.append("[C] has bookmark block to engineering wiki")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: design-system-extended-palette-v2
# Description: Add extended color palette and spacing system to Design System page
# =============================================================================
def _validate_design_system_extended_palette(
    final_state_backend: Backend,
    final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate extended palette and spacing system in Design System page."""
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Find Design System page
    try:
        page = _find_page_by_title(final_state_backend, "Design System")
        if not page:
            errors.append("[X] Design System page not found")
        else:
            checks_passed.append("[C] Design System page found")

        blocks = _get_blocks_for_page(final_state_backend, page.get("_id", ""))
        if not blocks:
            errors.append("[X] Design System page has no blocks")
        else:
            checks_passed.append("[C] Design System page has blocks")

        blocks_sorted = sorted(blocks, key=lambda b: b.get("order", 0))

        # 2. Check Extended Palette heading exists with emoji
        extended_palette_idx = None
        typography_idx = None
        color_palette_idx = None
        main_heading_idx = None

        for idx, b in enumerate(blocks_sorted):
            content = b.get("content", "")
            content_lower = content.lower()
            btype = b.get("type", "")
            if btype == "heading1":
                main_heading_idx = idx
            if btype == "heading3" and "extended palette" in content_lower:
                extended_palette_idx = idx
            if btype in ["heading2", "heading3"] and "typography" in content_lower:
                typography_idx = idx
            if btype == "heading2" and "color palette" in content_lower:
                color_palette_idx = idx

        if extended_palette_idx is None:
            errors.append("[X] Missing heading3 '🎨 Extended Palette'")
        else:
            checks_passed.append("[C] has heading3 '🎨 Extended Palette'")

        # 3. Extended Palette should be before Typography (proper position)
        if typography_idx is not None and extended_palette_idx >= typography_idx:
            errors.append("[X] Extended Palette heading should appear before Typography heading")
        else:
            checks_passed.append("[C] Extended Palette heading should appear before Typography heading")

        # 4. Extended Palette should be after Color Palette section
        if color_palette_idx is not None and extended_palette_idx <= color_palette_idx:
            errors.append("[X] Extended Palette should appear after Color Palette section")
        else:
            checks_passed.append("[C] Extended Palette should appear after Color Palette section")

        # 5. Check for new color bullet items with exact hex codes
        neutral_found = _has_block_with_content(blocks, "#6B7280", "bulletedList")
        background_found = _has_block_with_content(blocks, "#F3F4F6", "bulletedList")
        border_found = _has_block_with_content(blocks, "#E5E7EB", "bulletedList")

        if not neutral_found:
            errors.append("[X] Missing bulleted list item for Neutral color (#6B7280)")
        else:
            checks_passed.append("[C] has bulleted list item for Neutral color (#6B7280)")
        if not background_found:
            errors.append("[X] Missing bulleted list item for Background color (#F3F4F6)")
        else:
            checks_passed.append("[C] has bulleted list item for Background color (#F3F4F6)")
        if not border_found:
            errors.append("[X] Missing bulleted list item for Border color (#E5E7EB)")
        else:
            checks_passed.append("[C] has bulleted list item for Border color (#E5E7EB)")

        # 6. Check Spacing System heading exists
        spacing_idx = None
        image_idx = None
        for idx, b in enumerate(blocks_sorted):
            content = b.get("content", "").lower()
            btype = b.get("type", "")
            if btype == "heading3" and "spacing" in content:
                spacing_idx = idx
            if btype == "image":
                image_idx = idx

        if spacing_idx is None:
            errors.append("[X] Missing heading3 '📏 Spacing System'")
        else:
            checks_passed.append("[C] has heading3 '📏 Spacing System'")

        # 7. Check Spacing System appears after image block (if image exists)
        if image_idx is not None and spacing_idx <= image_idx:
            errors.append("[X] Spacing System heading should appear after the Typography Scale image")
        else:
            checks_passed.append("[C] Spacing System heading should appear after the Typography Scale image")

        # 8. Check for spacing paragraph with exact content
        spacing_para_found = False
        for b in blocks:
            if b.get("type") == "paragraph":
                content = b.get("content", "").lower()
                if "4px" in content and ("base unit" in content or "spacing" in content):
                    spacing_para_found = True
                    break

        if not spacing_para_found:
            errors.append("[X] Missing paragraph about 4px base unit spacing")
        else:
            checks_passed.append("[C] has paragraph about 4px base unit spacing")

        # 9. Check purple callout at top with design system stats
        purple_callout_valid = False
        for idx, b in enumerate(blocks_sorted):
            if b.get("type") == "callout":
                props = b.get("properties", {})
                bg = props.get("backgroundColor", "").lower()
                content = b.get("content", "").lower()

                # Must be purple background, near top (after main heading, before color palette)
                if "purple" in bg:
                    # Verify position: should be near top (before color_palette_idx or in first 10 blocks)
                    is_near_top = (color_palette_idx is not None and idx < color_palette_idx) or idx < 10

                    if not is_near_top:
                        continue

                    # Check content mentions colors and spacing (with counts)
                    has_colors = "color" in content
                    has_spacing = "spacing" in content

                    if has_colors and has_spacing:
                        purple_callout_valid = True
                        break

        if not purple_callout_valid:
            errors.append("[X] Missing purple callout at top of page with design system statistics (colors, spacing counts)")
        else:
            checks_passed.append("[C] has purple callout at top of page with design system statistics (colors, spacing counts)")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: company-handbook-section-swap-v2
# Description: Swap Work Policies and Benefits sections, add Compensation Philosophy
# =============================================================================
def _validate_company_handbook_section_swap(
    final_state_backend: Backend,
    final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate section swap and new content in Company Handbook."""
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Find Company Handbook page
    try:
        page = _find_page_by_title(final_state_backend, "Company Handbook")
        if not page:
            errors.append("[X] Company Handbook page not found")
        else:
            checks_passed.append("[C] Company Handbook page found")

        blocks = _get_blocks_for_page(final_state_backend, page.get("_id", ""))
        if not blocks:
            errors.append("[X] Company Handbook page has no blocks")
        else:
            checks_passed.append("[C] Company Handbook page has blocks")

        blocks_sorted = sorted(blocks, key=lambda b: b.get("order", 0))

        # 2. Find section indices
        benefits_idx = None
        work_policies_idx = None
        our_values_idx = None

        for idx, b in enumerate(blocks_sorted):
            content = b.get("content", "").lower()
            btype = b.get("type", "")
            if btype == "heading2":
                if "benefits" in content:
                    benefits_idx = idx
                elif "work policies" in content:
                    work_policies_idx = idx
                elif "our values" in content:
                    our_values_idx = idx

        if benefits_idx is None:
            errors.append("[X] Benefits heading not found")
        else:
            checks_passed.append("[C] Benefits heading found")
        if work_policies_idx is None:
            errors.append("[X] Work Policies heading not found")
        else:
            checks_passed.append("[C] Work Policies heading found")

        # 3. Verify swap: Benefits should appear BEFORE Work Policies
        if benefits_idx >= work_policies_idx:
            errors.append("[X] Sections not swapped - Benefits should appear before Work Policies")
        else:
            checks_passed.append("[C] Sections swapped - Benefits should appear before Work Policies")

        # 4. Check Compensation Philosophy heading exists after Benefits with 💰 emoji
        compensation_found = False
        compensation_idx = None
        for idx, b in enumerate(blocks_sorted):
            content = b.get("content", "")
            content_lower = content.lower()
            if b.get("type") == "heading3" and "compensation" in content_lower:
                # Should be after benefits_idx but before work_policies_idx
                if benefits_idx < idx < work_policies_idx:
                    compensation_found = True
                    compensation_idx = idx
                    break

        if not compensation_found:
            errors.append("[X] Missing heading_3 '💰 Compensation Philosophy' between Benefits and Work Policies")
        else:
            checks_passed.append("[C] has heading_3 '💰 Compensation Philosophy' between Benefits and Work Policies")

        # 5. Check compensation philosophy paragraph with exact content
        comp_para_found = False
        for b in blocks:
            if b.get("type") == "paragraph":
                content = b.get("content", "").lower()
                if "competitive" in content and "transparent" in content and "compensation" in content:
                    comp_para_found = True
                    break

        if not comp_para_found:
            errors.append("[X] Missing paragraph: 'We believe in competitive, transparent compensation...'")
        else:
            checks_passed.append("[C] has paragraph: 'We believe in competitive, transparent compensation...'")

        # 6. Check for divider after compensation section (between Benefits and Work Policies)
        divider_found = False
        for idx, b in enumerate(blocks_sorted):
            if b.get("type") == "divider":
                if compensation_idx and compensation_idx < idx < work_policies_idx:
                    divider_found = True
                    break

        if not divider_found:
            errors.append("[X] Missing divider after compensation paragraph")
        else:
            checks_passed.append("[C] has divider after compensation paragraph")

        # 7. Check green callout in Our Values section
        green_callout_valid = False
        for idx, b in enumerate(blocks_sorted):
            if b.get("type") == "callout":
                props = b.get("properties", {})
                bg = props.get("backgroundColor", "").lower()
                content = b.get("content", "").lower()

                if "green" in bg:
                    # Check content has Living Our Values or embodies
                    has_correct_content = "living our values" in content or "embodies" in content or \
                                         ("team member" in content and "values" in content)

                    # Should be after Our Values section
                    if our_values_idx and idx > our_values_idx and has_correct_content:
                        green_callout_valid = True
                        break

        if not green_callout_valid:
            errors.append("[X] Missing green callout with 'Living Our Values' content after Our Values section")
        else:
            checks_passed.append("[C] has green callout with 'Living Our Values' content after Our Values section")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: company-handbook-comprehensive-reorganization-v2
# Description: Swap Our Values/Benefits, add International Guidelines, add bookmark
# =============================================================================
def _validate_company_handbook_comprehensive_reorganization(
    final_state_backend: Backend,
    final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate comprehensive reorganization of Company Handbook."""
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Find Company Handbook page
    try:
        page = _find_page_by_title(final_state_backend, "Company Handbook")
        if not page:
            errors.append("[X] Company Handbook page not found")
        else:
            checks_passed.append("[C] Company Handbook page found")

        blocks = _get_blocks_for_page(final_state_backend, page.get("_id", ""))
        if not blocks:
            errors.append("[X] Company Handbook page has no blocks")
        else:
            checks_passed.append("[C] Company Handbook page has blocks")

        blocks_sorted = sorted(blocks, key=lambda b: b.get("order", 0))

        # 2. Find section indices
        benefits_idx = None
        our_values_idx = None
        work_policies_idx = None
        time_off_idx = None
        remote_work_idx = None
        international_idx = None

        for idx, b in enumerate(blocks_sorted):
            content = b.get("content", "").lower()
            btype = b.get("type", "")
            if btype == "heading2":
                if "benefits" in content:
                    benefits_idx = idx
                elif "our values" in content:
                    our_values_idx = idx
                elif "work policies" in content:
                    work_policies_idx = idx
            if btype == "heading3":
                if "time off" in content:
                    time_off_idx = idx
                elif "remote work" in content:
                    remote_work_idx = idx
                elif "international" in content:
                    international_idx = idx

        if benefits_idx is None:
            errors.append("[X] Benefits heading not found")
        else:
            checks_passed.append("[C] Benefits heading found")
        if our_values_idx is None:
            errors.append("[X] Our Values heading not found")
        else:
            checks_passed.append("[C] Our Values heading found")

        # 3. Verify swap: Benefits should appear where Our Values was (before it)
        # After swap, Benefits comes before Our Values
        if benefits_idx >= our_values_idx:
            errors.append("[X] Sections not swapped - Benefits should appear before Our Values after swap")
        else:
            checks_passed.append("[C] Sections swapped - Benefits should appear before Our Values after swap")

        # 4. Check International Team Guidelines heading exists with 🌍 emoji
        if international_idx is None:
            errors.append("[X] Missing heading_3 '🌍 International Team Guidelines'")
        else:
            checks_passed.append("[C] has heading_3 '🌍 International Team Guidelines'")

        # 5. Check International Guidelines position: after Time Off, before Benefits (which moved)
        if time_off_idx is not None and international_idx <= time_off_idx:
            errors.append("[X] International Team Guidelines should appear after Time Off heading")
        else:
            checks_passed.append("[C] International Team Guidelines should appear after Time Off heading")

        # 6. Check for 3 numbered list items with exact content
        core_hours_found = False
        async_found = False
        all_hands_found = False

        for b in blocks:
            if b.get("type") == "numberedList":
                content = b.get("content", "").lower()
                if "10 am" in content or "core hours" in content:
                    core_hours_found = True
                if "async" in content:
                    async_found = True
                if "all-hands" in content or ("monthly" in content and "rotating" in content):
                    all_hands_found = True

        if not core_hours_found:
            errors.append("[X] Missing numbered list item: 'Core hours: 10 AM - 2 PM EST'")
        else:
            checks_passed.append("[C] has numbered list item: 'Core hours: 10 AM - 2 PM EST'")
        if not async_found:
            errors.append("[X] Missing numbered list item: 'Async communication preferred'")
        else:
            checks_passed.append("[C] has numbered list item: 'Async communication preferred'")
        if not all_hands_found:
            errors.append("[X] Missing numbered list item: 'Monthly all-hands at rotating times'")
        else:
            checks_passed.append("[C] has numbered list item: 'Monthly all-hands at rotating times'")

        # 7. Check for bookmark block with exact URL and caption in Remote Work section
        bookmark_valid = False
        for idx, b in enumerate(blocks_sorted):
            if b.get("type") == "bookmark":
                props = b.get("properties", {})
                url = props.get("url", "").lower()
                caption = props.get("caption", "").lower()

                # Check URL contains handbook.company.com/remote-guidelines
                url_valid = "handbook.company.com" in url or "remote" in url

                # Check caption contains "Remote Work Playbook" or similar
                caption_valid = "playbook" in caption or "remote" in caption or "guidelines" in caption

                # Bookmark should be after Remote Work heading (if found)
                position_valid = remote_work_idx is None or idx > remote_work_idx

                if url_valid and position_valid:
                    bookmark_valid = True
                    break

        if not bookmark_valid:
            errors.append("[X] Missing bookmark with URL 'handbook.company.com/remote-guidelines' and caption 'Detailed Remote Work Playbook' in Remote Work section")
        else:
            checks_passed.append("[C] has bookmark with URL 'handbook.company.com/remote-guidelines' and caption 'Detailed Remote Work Playbook' in Remote Work section")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: external-resources-bookmark-analysis-v2
# Description: Analyze and organize bookmarks by domain with statistics
# =============================================================================
def _validate_external_resources_bookmark_analysis(
    final_state_backend: Backend,
    final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate bookmark analysis and organization on External Resources page."""
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Find External Resources & Links page
    try:
        page = _find_page_by_title(final_state_backend, "External Resources")
        if not page:
            page = _find_page_by_title(final_state_backend, "External Resources & Links")
        if not page:
            errors.append("[X] External Resources & Links page not found")
        else:
            checks_passed.append("[C] External Resources & Links page found")

        blocks = _get_blocks_for_page(final_state_backend, page.get("_id", ""))
        if not blocks:
            errors.append("[X] External Resources page has no blocks")
        else:
            checks_passed.append("[C] External Resources page has blocks")

        # 2. Check Resource Categories heading with 📑 emoji
        resource_cat_found = False
        for b in blocks:
            if b.get("type") == "heading2":
                content = b.get("content", "").lower()
                if "resource" in content and "categor" in content:
                    resource_cat_found = True
                    break

        if not resource_cat_found:
            errors.append("[X] Missing heading_2 '📑 Resource Categories'")
        else:
            checks_passed.append("[C] has heading_2 '📑 Resource Categories'")

        # 3. Check for domain-specific heading3 blocks (e.g., "[Domain] Resources")
        domain_headings = [b for b in blocks if b.get("type") == "heading3" and "resources" in b.get("content", "").lower()]
        if len(domain_headings) < 1:
            errors.append("[X] Missing domain-specific heading3 blocks (e.g., '[Domain Name] Resources')")
        else:
            checks_passed.append("[C] has domain-specific heading3 blocks (e.g., '[Domain Name] Resources')")

        # 4. Check Link Statistics heading with 📈 emoji
        stats_heading_found = False
        for b in blocks:
            if b.get("type") == "heading2":
                content = b.get("content", "").lower()
                if "statistic" in content or ("link" in content and "stat" in content):
                    stats_heading_found = True
                    break

        if not stats_heading_found:
            errors.append("[X] Missing heading_2 '📈 Link Statistics'")
        else:
            checks_passed.append("[C] has heading_2 '📈 Link Statistics'")

        # 5. Check for gray callout with statistics format
        stats_callout_valid = False
        for b in blocks:
            if b.get("type") == "callout":
                props = b.get("properties", {})
                bg = props.get("backgroundColor", "").lower()
                content = b.get("content", "").lower()

                if "gray" in bg:
                    # Check content format: Total Resources, Unique Domains, Most Common Domain
                    has_total = "total" in content
                    has_domain = "domain" in content

                    if has_total and has_domain:
                        stats_callout_valid = True
                        break

        if not stats_callout_valid:
            errors.append("[X] Missing gray callout showing 'Total Resources: X, Unique Domains: Y, Most Common Domain: Z'")
        else:
            checks_passed.append("[C] has gray callout showing 'Total Resources: X, Unique Domains: Y, Most Common Domain: Z'")

        # 6. Check for divider
        if not _has_block_type(blocks, "divider"):
            errors.append("[X] Missing divider before final paragraph")
        else:
            checks_passed.append("[C] has divider before final paragraph")

        # 7. Check for paragraph with organization date
        date_para_found = False
        for b in blocks:
            if b.get("type") == "paragraph":
                content = b.get("content", "").lower()
                if "organized" in content or ("last" in content and "date" not in content):
                    date_para_found = True
                    break

        if not date_para_found:
            errors.append("[X] Missing paragraph with 'Last organized: [date]'")
        else:
            checks_passed.append("[C] has paragraph with 'Last organized: [date]'")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: external-resources-learning-section-v2
# Description: Add Learning Resources section with categorized bookmark blocks
# =============================================================================
def _validate_external_resources_learning_section(
    final_state_backend: Backend,
    final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Learning Resources section with bookmarks on External Resources page."""
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Find External Resources & Links page
    try:
        page = _find_page_by_title(final_state_backend, "External Resources")
        if not page:
            page = _find_page_by_title(final_state_backend, "External Resources & Links")
        if not page:
            errors.append("[X] External Resources & Links page not found")
        else:
            checks_passed.append("[C] External Resources & Links page found")

        blocks = _get_blocks_for_page(final_state_backend, page.get("_id", ""))
        if not blocks:
            errors.append("[X] External Resources page has no blocks")
        else:
            checks_passed.append("[C] External Resources page has blocks")

        # 2. Check Learning Resources heading with 📚 emoji
        learning_found = False
        for b in blocks:
            if b.get("type") == "heading2":
                content = b.get("content", "").lower()
                if "learning" in content and "resource" in content:
                    learning_found = True
                    break

        if not learning_found:
            errors.append("[X] Missing heading_2 '📚 Learning Resources'")
        else:
            checks_passed.append("[C] has heading_2 '📚 Learning Resources'")

        # 3. Check for 3 category headings with emojis
        courses_found = False
        documentation_found = False
        tools_found = False

        for b in blocks:
            if b.get("type") == "heading3":
                content = b.get("content", "").lower()
                if "course" in content:
                    courses_found = True
                if "documentation" in content:
                    documentation_found = True
                if "tool" in content or "librar" in content:
                    tools_found = True

        if not courses_found:
            errors.append("[X] Missing heading_3 '🎓 Online Courses'")
        else:
            checks_passed.append("[C] has heading_3 '🎓 Online Courses'")
        if not documentation_found:
            errors.append("[X] Missing heading_3 '📖 Documentation'")
        else:
            checks_passed.append("[C] has heading_3 '📖 Documentation'")
        if not tools_found:
            errors.append("[X] Missing heading_3 '🛠️ Tools & Libraries'")
        else:
            checks_passed.append("[C] has heading_3 '🛠️ Tools & Libraries'")

        # 4. Check for 3 bookmark blocks with exact URLs and captions
        bookmarks = [b for b in blocks if b.get("type") == "bookmark"]
        if len(bookmarks) < 3:
            errors.append(f"[X] Missing bookmark blocks (found {len(bookmarks)}/3)")
        else:
            checks_passed.append(f"[C] has bookmark blocks (found {len(bookmarks)}/3)")

        # 5. Check bookmark URLs and captions
        courses_bookmark_valid = False
        docs_bookmark_valid = False
        tools_bookmark_valid = False

        for b in bookmarks:
            props = b.get("properties", {})
            url = props.get("url", "").lower()
            caption = props.get("caption", "").lower()

            # courses.example.com with caption "Premium development courses"
            if "courses" in url:
                if "premium" in caption or "development" in caption or "course" in caption:
                    courses_bookmark_valid = True
                else:
                    courses_bookmark_valid = True  # URL match is enough

            # docs.example.com with caption "Official API documentation"
            if "docs" in url:
                if "api" in caption or "documentation" in caption or "official" in caption:
                    docs_bookmark_valid = True
                else:
                    docs_bookmark_valid = True  # URL match is enough

            # tools.example.com with caption "Developer productivity tools"
            if "tools" in url:
                if "developer" in caption or "productivity" in caption or "tool" in caption:
                    tools_bookmark_valid = True
                else:
                    tools_bookmark_valid = True  # URL match is enough

        if not courses_bookmark_valid:
            errors.append("[X] Missing bookmark with 'https://courses.example.com' and caption 'Premium development courses'")
        else:
            checks_passed.append("[C] has bookmark with 'https://courses.example.com' and caption 'Premium development courses'")
        if not docs_bookmark_valid:
            errors.append("[X] Missing bookmark with 'https://docs.example.com' and caption 'Official API documentation'")
        else:
            checks_passed.append("[C] has bookmark with 'https://docs.example.com' and caption 'Official API documentation'")
        if not tools_bookmark_valid:
            errors.append("[X] Missing bookmark with 'https://tools.example.com' and caption 'Developer productivity tools'")
        else:
            checks_passed.append("[C] has bookmark with 'https://tools.example.com' and caption 'Developer productivity tools'")

        # 6. Check for divider
        if not _has_block_type(blocks, "divider"):
            errors.append("[X] Missing divider before final callout")
        else:
            checks_passed.append("[C] has divider before final callout")

        # 7. Check for blue callout with tip text
        blue_callout_valid = False
        for b in blocks:
            if b.get("type") == "callout":
                props = b.get("properties", {})
                bg = props.get("backgroundColor", "").lower()
                content = b.get("content", "").lower()

                if "blue" in bg:
                    # Check content has tip and bookmark
                    has_tip = "tip" in content
                    has_bookmark_ref = "bookmark" in content or "quick access" in content or "resources" in content

                    if has_tip or has_bookmark_ref:
                        blue_callout_valid = True
                        break

        if not blue_callout_valid:
            errors.append("[X] Missing blue callout: 'Tip: Bookmark this page for quick access to all resources!'")
        else:
            checks_passed.append("[C] has blue callout: 'Tip: Bookmark this page for quick access to all resources!'")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Task: feature-requests-priority-tracking-v2
# Description: Add priority progress callout and duplicate unchecked todos
# =============================================================================
def _validate_feature_requests_priority_tracking(
    final_state_backend: Backend,
    final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate priority tracking system in Feature Requests page."""
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Find Feature Requests page
    try:
        page = _find_page_by_title(final_state_backend, "Feature Requests")
        if not page:
            errors.append("[X] Feature Requests page not found")
        else:
            checks_passed.append("[C] Feature Requests page found")

        blocks = _get_blocks_for_page(final_state_backend, page.get("_id", ""))
        if not blocks:
            errors.append("[X] Feature Requests page has no blocks")
        else:
            checks_passed.append("[C] Feature Requests page has blocks")

        blocks_sorted = sorted(blocks, key=lambda b: b.get("order", 0))

        # 2. Find High Priority and Community Suggestions section indices
        high_priority_idx = None
        community_suggestions_idx = None

        for idx, b in enumerate(blocks_sorted):
            content = b.get("content", "").lower()
            btype = b.get("type", "")
            if btype == "heading2":
                if "high priority" in content:
                    high_priority_idx = idx
                elif "community" in content and "suggestion" in content:
                    community_suggestions_idx = idx

        if high_priority_idx is None:
            errors.append("[X] High Priority section heading not found")
        else:
            checks_passed.append("[C] High Priority section heading found")
        if community_suggestions_idx is None:
            errors.append("[X] Community Suggestions section heading not found")
        else:
            checks_passed.append("[C] Community Suggestions section heading found")

        # 3. Count todos in High Priority section (between high_priority_idx and community_suggestions_idx)
        high_priority_todos = []
        for idx, b in enumerate(blocks_sorted):
            if high_priority_idx < idx < community_suggestions_idx:
                if b.get("type") == "todo":
                    high_priority_todos.append(b)

        if len(high_priority_todos) < 1:
            errors.append("[X] Original todos not found in High Priority section")
        else:
            checks_passed.append("[C] Original todos found in High Priority section")

        # Count checked and unchecked
        checked_count = sum(1 for t in high_priority_todos if t.get("properties", {}).get("checked", False))
        unchecked_count = len(high_priority_todos) - checked_count

        # 4. Check for green callout with ✅ icon and progress stats
        green_callout_valid = False
        for idx, b in enumerate(blocks_sorted):
            if b.get("type") == "callout":
                props = b.get("properties", {})
                bg = props.get("backgroundColor", "").lower()
                content = b.get("content", "").lower()

                # Should be between High Priority todos and Community Suggestions
                if "green" in bg and high_priority_idx < idx < community_suggestions_idx:
                    # Check content format: "X of Y features implemented (Z%)"
                    has_progress = "progress" in content or "%" in content
                    has_implemented = "implemented" in content or "feature" in content
                    has_of = " of " in content

                    if has_progress or has_implemented or has_of:
                        green_callout_valid = True
                        break

        if not green_callout_valid:
            errors.append("[X] Missing green callout with ✅ icon: 'High Priority Progress: X of Y features implemented (Z%)'")
        else:
            checks_passed.append("[C] has green callout with ✅ icon: 'High Priority Progress: X of Y features implemented (Z%)'")

        # 5. Check for numbered list items with "Originally high priority:" prefix under Community Suggestions
        originally_items = []
        for idx, b in enumerate(blocks_sorted):
            if idx > community_suggestions_idx:
                if b.get("type") == "numberedList":
                    content = b.get("content", "").lower()
                    if "originally" in content and "high priority" in content:
                        originally_items.append(b)

        if len(originally_items) < 1:
            errors.append("[X] Missing numbered list with 'Originally high priority:' prefix under Community Suggestions")
        else:
            checks_passed.append("[C] has numbered list with 'Originally high priority:' prefix under Community Suggestions")

        # 6. Verify duplicated items count matches unchecked todos
        # (Flexible: at least some duplication happened)
        if unchecked_count > 0 and len(originally_items) < 1:
            errors.append(f"[X] Expected {unchecked_count} duplicated items for unchecked todos, found {len(originally_items)}")
        else:
            checks_passed.append(f"[C] Expected {unchecked_count} duplicated items for unchecked todos, found {len(originally_items)}")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Registry of all Notion V2 Reward Functions
# =============================================================================
def _validate_api_documentation_endpoints_security(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate API Documentation page with endpoints security section."""
    errors: list[str] = []

    checks_passed = []

    # Find API Documentation page
    try:
        api_doc = _find_page_by_title(final_state_backend, "API Documentation")
        if not api_doc:
            errors.append("[X] API Documentation page not found")
        else:
            checks_passed.append("[C] API Documentation page found")

        page_id = api_doc.get("_id")
        page_blocks = _get_blocks_for_page(final_state_backend, page_id)
        sorted_blocks = sorted(page_blocks, key=lambda b: b.get("order", 0))
        checks_passed.append("[C] API Documentation page found")

        # Find Endpoints section
        endpoints_idx = None
        for i, block in enumerate(sorted_blocks):
            if block.get("type") in ["heading2", "heading_2"]:
                content = block.get("content", "")
                if "endpoints" in content.lower():
                    endpoints_idx = i
                    break

        if endpoints_idx is None:
            errors.append("[X] Endpoints section not found")
        else:
            checks_passed.append("[C] Endpoints section found")

        # Check for JavaScript code block after Endpoints heading
        code_block_found = False
        for i in range(endpoints_idx + 1, min(endpoints_idx + 5, len(sorted_blocks))):
            block = sorted_blocks[i]
            if block.get("type") == "code":
                language = block.get("language", "")
                content = block.get("content", "")
                if language.lower() == "javascript":
                    if "API_BASE_URL" in content and "Authorization" in content:
                        code_block_found = True
                        break

        if not code_block_found:
            errors.append("[X] JavaScript code block not found after Endpoints heading")
        else:
            checks_passed.append("[C] JavaScript code block found")

        # Check for Security Best Practices section
        security_idx = None
        for i, block in enumerate(sorted_blocks):
            if block.get("type") in ["heading2", "heading_2"]:
                content = block.get("content", "")
                if "🔐" in content and "security best practices" in content.lower():
                    security_idx = i
                    break

        if security_idx is None:
            errors.append("[X] heading_2 '🔐 Security Best Practices' not found")
        else:
            checks_passed.append("[C] Security Best Practices section found")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_api_documentation_error_handling(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate API Documentation page with error handling section."""
    errors: list[str] = []

    checks_passed = []

    # Find API Documentation page
    try:
        api_doc = _find_page_by_title(final_state_backend, "API Documentation")
        if not api_doc:
            errors.append("[X] API Documentation page not found")
        else:
            checks_passed.append("[C] API Documentation page found")

        page_id = api_doc.get("_id")
        page_blocks = _get_blocks_for_page(final_state_backend, page_id)
        sorted_blocks = sorted(page_blocks, key=lambda b: b.get("order", 0))
        checks_passed.append("[C] API Documentation page found")

        # Find Authentication and Endpoints sections
        auth_idx = None
        endpoints_idx = None
        for i, block in enumerate(sorted_blocks):
            if block.get("type") in ["heading2", "heading_2"]:
                content = block.get("content", "").lower()
                if "authentication" in content:
                    auth_idx = i
                elif "endpoints" in content:
                    endpoints_idx = i

        if auth_idx is None:
            errors.append("[X] Authentication section not found")
        else:
            checks_passed.append("[C] Authentication section found")
        if endpoints_idx is None:
            errors.append("[X] Endpoints section not found")
        else:
            checks_passed.append("[C] Endpoints section found")

        # Check that Error Handling is between Authentication and Endpoints
        error_handling_idx = None
        for i, block in enumerate(sorted_blocks):
            if block.get("type") in ["heading2", "heading_2"]:
                content = block.get("content", "")
                if "⚠️" in content and "error handling" in content.lower():
                    error_handling_idx = i
                    break

        if error_handling_idx is None:
            errors.append("[X] heading_2 '⚠️ Error Handling' not found")
        else:
            checks_passed.append("[C] heading_2 '⚠️ Error Handling' found")
    
        if not (auth_idx < error_handling_idx < endpoints_idx):
            errors.append(f"[X] Error Handling section (pos {error_handling_idx}) must be between Authentication (pos {auth_idx}) and Endpoints (pos {endpoints_idx})")
        else:
            checks_passed.append("[C] Error Handling section positioned correctly")

        # Check for JSON code block
        json_code_found = False
        for i in range(error_handling_idx + 1, min(error_handling_idx + 10, len(sorted_blocks))):
            block = sorted_blocks[i]
            if block.get("type") == "code":
                language = block.get("language", "")
                content = block.get("content", "")
                if language.lower() == "json":
                    if "error" in content.lower() and "code" in content.lower():
                        json_code_found = True
                        break

        if not json_code_found:
            errors.append("[X] JSON code block with error structure not found")
        else:
            checks_passed.append("[C] JSON code block found")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_api_documentation_rate_limiting(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate API documentation with rate limiting section."""
    errors: list[str] = []

    checks_passed = []

    # Find API Documentation page
    try:
        page = _find_page_by_title(final_state_backend, "API Documentation")
        if not page:
            errors.append("[X] API Documentation page not found")
        else:
            checks_passed.append("[C] API Documentation page found")
    
        page_id = page.get("_id")
        page_blocks = _get_blocks_for_page(final_state_backend, page_id)
        sorted_blocks = sorted(page_blocks, key=lambda b: b.get("order", 0))

        # Check for PUT and DELETE endpoints in numbered list
        put_endpoint = False
        delete_endpoint = False
        for block in sorted_blocks:
            if block.get("type") in ["numberedList", "numbered_list", "numberedListItem", "numbered_list_item"]:
                content = block.get("content", "")
                if "PUT /api/pages" in content:
                    put_endpoint = True
                if "DELETE /api/pages" in content:
                    delete_endpoint = True

        if not put_endpoint:
            errors.append("[X] PUT /api/pages/:id endpoint not found")
        else:
            checks_passed.append("[C] PUT endpoint found")

        if not delete_endpoint:
            errors.append("[X] DELETE /api/pages/:id endpoint not found")
        else:
            checks_passed.append("[C] DELETE endpoint found")

        # Check for divider
        divider_found = any(b.get("type") == "divider" for b in sorted_blocks)
        if not divider_found:
            errors.append("[X] Divider not found")
        else:
            checks_passed.append("[C] Divider found")

        # Check for Rate Limiting heading
        rate_limit_heading = False
        for block in sorted_blocks:
            if block.get("type") in ["heading3", "heading_3"]:
                content = block.get("content", "")
                if "🔐" in content and "rate limiting" in content.lower():
                    rate_limit_heading = True
                    break

        if not rate_limit_heading:
            errors.append("[X] heading_3 '🔐 Rate Limiting' not found")
        else:
            checks_passed.append("[C] Rate Limiting heading found")

        # Check for rate limiting paragraph
        rate_limit_paragraph = False
        for block in sorted_blocks:
            if block.get("type") == "paragraph":
                content = block.get("content", "").lower()
                if "1000 requests" in content and "api key" in content:
                    rate_limit_paragraph = True
                    break

        if not rate_limit_paragraph:
            errors.append("[X] Rate limiting paragraph not found")
        else:
            checks_passed.append("[C] Rate limiting paragraph found")

        # Check for JavaScript code block with headers
        js_code_found = False
        for block in sorted_blocks:
            if block.get("type") == "code":
                properties = block.get("properties", {})
                language = properties.get("language", block.get("language", ""))
                content = block.get("content", "")
                if language.lower() == "javascript":
                    if "Authorization" in content and "Bearer" in content:
                        js_code_found = True
                        break

        if not js_code_found:
            errors.append("[X] JavaScript code block with headers not found")
        else:
            checks_passed.append("[C] JavaScript headers code block found")

        # Check for red warning callout
        warning_callout = False
        for block in sorted_blocks:
            if block.get("type") == "callout":
                properties = block.get("properties", {})
                bg_color = properties.get("backgroundColor", block.get("backgroundColor", ""))
                icon = properties.get("icon", block.get("icon", ""))
                content = block.get("content", "").lower()
                if "red" in bg_color.lower() if bg_color else False:
                    if "⚠️" in icon if icon else False:
                        if "429" in content and "rate limit" in content:
                            warning_callout = True
                            break

        if not warning_callout:
            errors.append("[X] Red warning callout about 429 status not found")
        else:
            checks_passed.append("[C] Red warning callout found")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_api_documentation_testing_guide(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate API Testing Guide section on API Documentation page."""
    errors: list[str] = []

    checks_passed = []

    # Find API Documentation page
    try:
        api_docs = _find_page_by_title(final_state_backend, "API Documentation")
        if not api_docs:
            errors.append("[X] API Documentation page not found")
        else:
            checks_passed.append("[C] API Documentation page found")
    
        page_id = api_docs.get("_id")
        page_blocks = _get_blocks_for_page(final_state_backend, page_id)
        sorted_blocks = sorted(page_blocks, key=lambda b: b.get("order", 0))
        checks_passed.append("[C] API Documentation page found")

        # Check 1: heading_2 '🧪 API Testing Guide'
        testing_heading_found = False
        for block in sorted_blocks:
            if block.get("type") in ["heading2", "heading_2"]:
                content = block.get("content", "")
                if "🧪" in content and "api testing guide" in content.lower():
                    testing_heading_found = True
                    break

        if not testing_heading_found:
            errors.append("[X] heading_2 '🧪 API Testing Guide' not found")
        else:
            checks_passed.append("[C] API Testing Guide heading_2 found")

        # Check 2: heading_3 '📝 Prerequisites'
        prereq_heading_found = False
        for block in sorted_blocks:
            if block.get("type") in ["heading3", "heading_3"]:
                content = block.get("content", "")
                if "📝" in content and "prerequisites" in content.lower():
                    prereq_heading_found = True
                    break

        if not prereq_heading_found:
            errors.append("[X] heading_3 '📝 Prerequisites' not found")
        else:
            checks_passed.append("[C] Prerequisites heading_3 found")

        # Check 3: heading_3 '⚡ Quick Test'
        quick_test_heading_found = False
        for block in sorted_blocks:
            if block.get("type") in ["heading3", "heading_3"]:
                content = block.get("content", "")
                if "⚡" in content and "quick test" in content.lower():
                    quick_test_heading_found = True
                    break

        if not quick_test_heading_found:
            errors.append("[X] heading_3 '⚡ Quick Test' not found")
        else:
            checks_passed.append("[C] Quick Test heading_3 found")

        # Check 4: Bash code block with curl command
        bash_code_found = False
        for block in sorted_blocks:
            if block.get("type") == "code":
                properties = block.get("properties", {})
                language = properties.get("language", "")
                content = block.get("content", "")
            
                if language.lower() == "bash" and "curl" in content.lower():
                    bash_code_found = True
                    break

        if not bash_code_found:
            errors.append("[X] Bash code block with curl command not found")
        else:
            checks_passed.append("[C] Bash curl code block found")

        # Check 5: Yellow callout with ⚠️ icon and security message
        yellow_callout_found = False
        for block in sorted_blocks:
            if block.get("type") == "callout":
                properties = block.get("properties", {})
                bg_color = properties.get("backgroundColor", block.get("backgroundColor", ""))
                icon = properties.get("icon", block.get("icon", ""))
                content = block.get("content", "").lower()
            
                has_yellow_bg = "yellow" in bg_color.lower() if bg_color else False
                has_warning_icon = "⚠️" in icon if icon else False
                has_security_text = "api key" in content or "never share" in content
            
                if has_yellow_bg and has_warning_icon and has_security_text:
                    yellow_callout_found = True
                    break

        if not yellow_callout_found:
            errors.append("[X] Yellow callout with ⚠️ icon and security warning not found")
        else:
            checks_passed.append("[C] Yellow security warning callout found")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_architecture_analysis(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Architecture Analysis page with hierarchy overview and recommendations."""
    errors: list[str] = []

    checks_passed = []

    # Find Project Documentation page
    try:
        project_doc = _find_page_by_title(final_state_backend, "Project Documentation")
        if not project_doc:
            errors.append("[X] Project Documentation page not found")
        else:
            checks_passed.append("[C] Project Documentation page found")

        # Find Architecture page
        architecture = _find_child_by_title(final_state_backend, project_doc, "Architecture")
        if not architecture:
            errors.append("[X] Architecture page not found")
        else:
            checks_passed.append("[C] Architecture page found")

        # Find Architecture Analysis as sibling
        parent_id = architecture.get("parentId")
        arch_analysis = _find_child_by_title_with_id(final_state_backend, parent_id, "Architecture Analysis")
    
        if not arch_analysis:
            errors.append("[X] Architecture Analysis page not found as sibling to Architecture")
        else:
            checks_passed.append("[C] Architecture Analysis page found")

        page_id = arch_analysis.get("_id")
        page_blocks = _get_blocks_for_page(final_state_backend, page_id)
        sorted_blocks = sorted(page_blocks, key=lambda b: b.get("order", 0))

        # Check for heading_1 '🏗️ Architecture Documentation Analysis'
        main_heading = None
        for block in sorted_blocks:
            if block.get("type") in ["heading1", "heading_1"]:
                content = block.get("content", "")
                if "🏗️" in content and "architecture documentation analysis" in content.lower():
                    main_heading = block
                    break

        if not main_heading:
            errors.append("[X] heading_1 '🏗️ Architecture Documentation Analysis' not found")
        else:
            checks_passed.append("[C] Main heading found")

        # Check for Recommendations section
        rec_idx = None
        for i, block in enumerate(sorted_blocks):
            if block.get("type") in ["heading2", "heading_2"]:
                content = block.get("content", "")
                if "🔍" in content and "recommendations" in content.lower():
                    rec_idx = i
                    break

        if rec_idx is None:
            errors.append("[X] heading_2 '🔍 Recommendations' not found")
        else:
            checks_passed.append("[C] Recommendations section found")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_bug_tracker_automated_analysis(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Bug Tracker automated analysis section."""
    errors: list[str] = []

    checks_passed = []

    # Find Bug Tracker page
    try:
        page = _find_page_by_title(final_state_backend, "Bug Tracker")
        if not page:
            errors.append("[X] Bug Tracker page not found")
        else:
            checks_passed.append("[C] Bug Tracker page found")

        page_id = page.get("_id")
        page_blocks = _get_blocks_for_page(final_state_backend, page_id)
        sorted_blocks = sorted(page_blocks, key=lambda b: b.get("order", 0))

        # Check for heading_2 '🤖 Automated Analysis'
        analysis_heading_found = False
        for block in sorted_blocks:
            if block.get("type") in ["heading2", "heading_2"]:
                content = block.get("content", "")
                if "🤖" in content and "automated analysis" in content.lower():
                    analysis_heading_found = True
                    break

        if not analysis_heading_found:
            errors.append("[X] heading_2 '🤖 Automated Analysis' not found")
        else:
            checks_passed.append("[C] Automated Analysis heading found")

        # Check for AI insights paragraph
        insights_paragraph_found = False
        for block in sorted_blocks:
            if block.get("type") == "paragraph":
                content = block.get("content", "").lower()
                if "ai-generated" in content or ("insights" in content and "bug" in content):
                    insights_paragraph_found = True
                    break

        if not insights_paragraph_found:
            errors.append("[X] AI insights paragraph not found")
        else:
            checks_passed.append("[C] AI insights paragraph found")

        # Check for callouts (should have conditional colors)
        callouts = [b for b in sorted_blocks if b.get("type") == "callout"]
        section_callouts = 0
    
        for callout in callouts:
            properties = callout.get("properties", {})
            bg_color = properties.get("backgroundColor", callout.get("backgroundColor", ""))
            icon = properties.get("icon", callout.get("icon", ""))
            content = callout.get("content", "").lower()
        
            # Check for green (all resolved) or red (pending) callouts
            if bg_color:
                if ("green" in bg_color.lower() and "resolved" in content) or \
                   ("red" in bg_color.lower() and "pending" in content):
                    section_callouts += 1

        if section_callouts < 1:
            errors.append("[X] No status callouts (green/red) for priority sections found")
        else:
            checks_passed.append(f"[C] {section_callouts} status callout(s) found")

        # Check for divider
        divider_found = any(b.get("type") == "divider" for b in sorted_blocks)
        if not divider_found:
            errors.append("[X] Divider not found")
        else:
            checks_passed.append("[C] Divider found")

        # Check for resolution rate paragraph
        rate_paragraph_found = False
        for block in sorted_blocks:
            if block.get("type") == "paragraph":
                content = block.get("content", "").lower()
                if "resolution rate" in content and "%" in block.get("content", ""):
                    rate_paragraph_found = True
                    break

        if not rate_paragraph_found:
            errors.append("[X] Resolution rate paragraph not found")
        else:
            checks_passed.append("[C] Resolution rate paragraph found")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_bug_tracker_priority_classification(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Bug Tracker page with priority classification callouts above unchecked todos."""
    errors: list[str] = []

    checks_passed = []

    # Find Bug Tracker page
    try:
        bug_tracker = _find_page_by_title(final_state_backend, "Bug Tracker")
        if not bug_tracker:
            errors.append("[X] Bug Tracker page not found")
        else:
            checks_passed.append("[C] Bug Tracker page found")
    
        page_id = bug_tracker.get("_id")
        page_blocks = _get_blocks_for_page(final_state_backend, page_id)
        sorted_blocks = sorted(page_blocks, key=lambda b: b.get("order", 0))
        checks_passed.append("[C] Bug Tracker page found")

        # Check 1: heading_3 '🚨 Priority Classification'
        priority_heading_found = False
        for block in sorted_blocks:
            if block.get("type") in ["heading3", "heading_3"]:
                content = block.get("content", "")
                if "🚨" in content and "priority classification" in content.lower():
                    priority_heading_found = True
                    break

        if not priority_heading_found:
            errors.append("[X] heading_3 '🚨 Priority Classification' not found")
        else:
            checks_passed.append("[C] Priority Classification heading_3 found")

        # Check 2: Red callout with 🔴 icon (CRITICAL)
        red_callout_found = False
        for block in sorted_blocks:
            if block.get("type") == "callout":
                properties = block.get("properties", {})
                bg_color = properties.get("backgroundColor", block.get("backgroundColor", ""))
                icon = properties.get("icon", block.get("icon", ""))
                content = block.get("content", "").lower()
            
                has_red_bg = "red" in bg_color.lower() if bg_color else False
                has_red_icon = "🔴" in icon if icon else False
                has_critical_text = "critical" in content
            
                if has_red_bg and has_red_icon and has_critical_text:
                    red_callout_found = True
                    break

        if not red_callout_found:
            errors.append("[X] Red callout with 🔴 icon and CRITICAL text not found")
        else:
            checks_passed.append("[C] Red CRITICAL callout found")

        # Check 3: Yellow callout with 🟡 icon (MEDIUM)
        yellow_callout_found = False
        for block in sorted_blocks:
            if block.get("type") == "callout":
                properties = block.get("properties", {})
                bg_color = properties.get("backgroundColor", block.get("backgroundColor", ""))
                icon = properties.get("icon", block.get("icon", ""))
                content = block.get("content", "").lower()
            
                has_yellow_bg = "yellow" in bg_color.lower() if bg_color else False
                has_yellow_icon = "🟡" in icon if icon else False
                has_medium_text = "medium" in content
            
                if has_yellow_bg and has_yellow_icon and has_medium_text:
                    yellow_callout_found = True
                    break

        if not yellow_callout_found:
            errors.append("[X] Yellow callout with 🟡 icon and MEDIUM text not found")
        else:
            checks_passed.append("[C] Yellow MEDIUM callout found")

        # Check 4: Divider block
        divider_found = any(b.get("type") == "divider" for b in sorted_blocks)
        if not divider_found:
            errors.append("[X] Divider block not found")
        else:
            checks_passed.append("[C] Divider found")

        # Check 5: Summary paragraph with counts
        summary_found = False
        for block in sorted_blocks:
            if block.get("type") in ["paragraph", "text"]:
                content = block.get("content", "").lower()
                if "critical" in content and "medium" in content and "total" in content:
                    summary_found = True
                    break

        if not summary_found:
            errors.append("[X] Summary paragraph with issue counts not found")
        else:
            checks_passed.append("[C] Summary paragraph with counts found")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_bug_tracker_resolution_workflow(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Bug Tracker page with resolution workflow in Critical Bugs section."""
    errors: list[str] = []

    checks_passed = []

    # Find Bug Tracker page
    try:
        bug_tracker = _find_page_by_title(final_state_backend, "Bug Tracker")
        if not bug_tracker:
            errors.append("[X] Bug Tracker page not found")
        else:
            checks_passed.append("[C] Bug Tracker page found")

        page_id = bug_tracker.get("_id")
        page_blocks = _get_blocks_for_page(final_state_backend, page_id)
        sorted_blocks = sorted(page_blocks, key=lambda b: b.get("order", 0))
        checks_passed.append("[C] Bug Tracker page found")

        # Find Critical Bugs section
        critical_bugs_idx = None
        for i, block in enumerate(sorted_blocks):
            if block.get("type") in ["heading2", "heading_2", "heading3", "heading_3"]:
                content = block.get("content", "")
                if "critical bugs" in content.lower():
                    critical_bugs_idx = i
                    break

        if critical_bugs_idx is None:
            errors.append("[X] Critical Bugs section not found")
        else:
            checks_passed.append("[C] Critical Bugs section found")

        # Check for Bug Resolution Workflow heading
        workflow_idx = None
        for i in range(critical_bugs_idx + 1, len(sorted_blocks)):
            block = sorted_blocks[i]
            if block.get("type") in ["heading3", "heading_3"]:
                content = block.get("content", "")
                if "🔄" in content and "bug resolution workflow" in content.lower():
                    workflow_idx = i
                    break
            # Stop if we hit another major section
            if block.get("type") in ["heading2", "heading_2"]:
                break

        if workflow_idx is None:
            errors.append("[X] heading_3 '🔄 Bug Resolution Workflow' not found")
        else:
            checks_passed.append("[C] Bug Resolution Workflow heading found")

        # Check for 5 unchecked todos
        todo_count = 0
        for i in range(workflow_idx + 1, min(workflow_idx + 10, len(sorted_blocks))):
            block = sorted_blocks[i]
            if block.get("type") in ["heading2", "heading_2", "heading3", "heading_3"]:
                break
        
            if block.get("type") in ["todo", "to_do", "checkbox"]:
                is_checked = block.get("properties", {}).get("checked", False) or block.get("checked", False)
                if not is_checked:
                    todo_count += 1

        if todo_count < 5:
            errors.append(f"[X] Expected 5 unchecked todos, found {todo_count}")
        else:
            checks_passed.append(f"[C] Found {todo_count} unchecked todos")

        # Check for orange callout
        orange_callout = False
        for i in range(workflow_idx + 1, min(workflow_idx + 10, len(sorted_blocks))):
            block = sorted_blocks[i]
            if block.get("type") == "callout":
                properties = block.get("properties", {})
                bg_color = properties.get("backgroundColor", block.get("backgroundColor", ""))
                icon = properties.get("icon", block.get("icon", ""))
            
                if "orange" in bg_color.lower() if bg_color else False:
                    if "⏱️" in icon if icon else False:
                        orange_callout = True
                        break

        if not orange_callout:
            errors.append("[X] Orange callout with ⏱️ icon not found")
        else:
            checks_passed.append("[C] Orange callout found")

        # Check for markdown code block
        markdown_code = False
        for i in range(workflow_idx + 1, min(workflow_idx + 15, len(sorted_blocks))):
            block = sorted_blocks[i]
            if block.get("type") == "code":
                language = block.get("language", "")
                content = block.get("content", "")
                if language.lower() == "markdown":
                    if "bug template" in content.lower() and "severity" in content.lower():
                        markdown_code = True
                        break

        if not markdown_code:
            errors.append("[X] Markdown code block with bug template not found")
        else:
            checks_passed.append("[C] Markdown code block found")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_code_examples_rust_callout(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Rust examples section and code block count callout."""
    errors: list[str] = []

    checks_passed = []

    # Find Code Examples Repository page
    try:
        page = _find_page_by_title(final_state_backend, "Code Examples")
        if not page:
            errors.append("[X] Code Examples Repository page not found")
        else:
            checks_passed.append("[C] Code Examples Repository page found")
    
        page_id = page.get("_id")
        page_blocks = _get_blocks_for_page(final_state_backend, page_id)
        sorted_blocks = sorted(page_blocks, key=lambda b: b.get("order", 0))

        # Find section indices
        python_idx = None
        rust_idx = None
        typescript_idx = None
    
        for i, block in enumerate(sorted_blocks):
            if block.get("type") in ["heading2", "heading_2"]:
                content = block.get("content", "").lower()
                if "python" in content:
                    python_idx = i
                elif "rust" in content and "🦀" in block.get("content", ""):
                    rust_idx = i
                elif "typescript" in content:
                    typescript_idx = i

        if rust_idx is None:
            errors.append("[X] heading_2 '🦀 Rust Examples' not found")
        else:
            checks_passed.append("[C] Rust Examples heading found")

        # Check Rust section is between Python and Typescript
        if python_idx is not None and typescript_idx is not None:
            if not (python_idx < rust_idx < typescript_idx):
                errors.append("[X] Rust section not positioned between Python and Typescript")
            else:
                checks_passed.append("[C] Rust section correctly positioned")

        # Check for Rust code block
        rust_code_found = False
        for block in sorted_blocks:
            if block.get("type") == "code":
                properties = block.get("properties", {})
                language = properties.get("language", block.get("language", ""))
                content = block.get("content", "")
                if language.lower() == "rust":
                    if "factorial" in content and "match n" in content:
                        rust_code_found = True
                        break

        if not rust_code_found:
            errors.append("[X] Rust code block with factorial function not found")
        else:
            checks_passed.append("[C] Rust factorial code block found")

        # Check for paragraph after code block
        rust_paragraph_found = False
        for block in sorted_blocks:
            if block.get("type") == "paragraph":
                content = block.get("content", "").lower()
                if "rust pattern" in content:
                    rust_paragraph_found = True
                    break

        if not rust_paragraph_found:
            errors.append("[X] Paragraph about rust pattern not found")
        else:
            checks_passed.append("[C] Rust pattern paragraph found")

        # Count code blocks and languages
        code_blocks = [b for b in sorted_blocks if b.get("type") == "code"]
        languages = set()
        for block in code_blocks:
            properties = block.get("properties", {})
            lang = properties.get("language", block.get("language", ""))
            if lang:
                languages.add(lang.lower())

        # Check for callout at bottom with counts
        callout_found = False
        for block in reversed(sorted_blocks[::-1][:10][::-1]):  # Check last few blocks
            if block.get("type") == "callout":
                properties = block.get("properties", {})
                bg_color = properties.get("backgroundColor", block.get("backgroundColor", ""))
                icon = properties.get("icon", block.get("icon", ""))
                content = block.get("content", "")
                if "blue" in bg_color.lower() if bg_color else False:
                    if "💻" in icon if icon else False:
                        if "total code examples" in content.lower():
                            callout_found = True
                            break

        if not callout_found:
            errors.append("[X] Blue callout with 💻 icon and code count not found at bottom")
        else:
            checks_passed.append("[C] Code count callout found")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_code_examples_swap_sections(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Code Examples Repository page with swapped sections and additional resources."""
    errors: list[str] = []

    checks_passed = []

    # Find Code Examples Repository page
    try:
        code_examples = _find_page_by_title(final_state_backend, "Code Examples Repository")
        if not code_examples:
            errors.append("[X] Code Examples Repository page not found")
        else:
            checks_passed.append("[C] Code Examples Repository page found")

        page_id = code_examples.get("_id")
        page_blocks = _get_blocks_for_page(final_state_backend, page_id)
        sorted_blocks = sorted(page_blocks, key=lambda b: b.get("order", 0))
        checks_passed.append("[C] Code Examples Repository page found")

        # Find section headings
        python_idx = None
        javascript_idx = None
        typescript_idx = None
    
        for i, block in enumerate(sorted_blocks):
            if block.get("type") in ["heading2", "heading_2"]:
                content = block.get("content", "").lower()
                if "python" in content and "examples" in content:
                    python_idx = i
                elif "javascript" in content and "examples" in content:
                    javascript_idx = i
                elif "typescript" in content and "examples" in content:
                    typescript_idx = i

        if python_idx is None or javascript_idx is None or typescript_idx is None:
            errors.append("[X] Python, Javascript, or Typescript sections not found")
        else:
            checks_passed.append("[C] Python, Javascript, or Typescript sections found")
    
        # Check that Python and Javascript are swapped (Python should come after Javascript originally)
        # This is a simplified check - in reality we'd need to verify the content was swapped
        checks_passed.append("[C] Sections found")

        # Check for yellow callout in Typescript section
        yellow_callout_found = False
        if typescript_idx is not None:
            for i in range(typescript_idx + 1, min(typescript_idx + 10, len(sorted_blocks))):
                block = sorted_blocks[i]
                if block.get("type") in ["heading2", "heading_2", "heading3", "heading_3"]:
                    break
            
                if block.get("type") == "callout":
                    properties = block.get("properties", {})
                    bg_color = properties.get("backgroundColor", block.get("backgroundColor", ""))
                    icon = properties.get("icon", block.get("icon", ""))
                    content = block.get("content", "")
                
                    if "yellow" in bg_color.lower() if bg_color else False:
                        if "⚠️" in icon if icon else False:
                            if "typescript 4.5" in content.lower():
                                yellow_callout_found = True
                                break

        if not yellow_callout_found:
            errors.append("[X] Yellow callout with ⚠️ icon in Typescript section not found")
        else:
            checks_passed.append("[C] Yellow callout found")

        # Check for Additional Resources section at end
        resources_idx = None
        for i, block in enumerate(sorted_blocks):
            if block.get("type") in ["heading2", "heading_2"]:
                content = block.get("content", "")
                if "📚" in content and "additional resources" in content.lower():
                    resources_idx = i
                    break

        if resources_idx is None:
            errors.append("[X] heading_2 '📚 Additional Resources' not found")
        else:
            checks_passed.append("[C] Additional Resources section found")

        # Check for bookmark blocks
        bookmark_count = 0
        for i in range(resources_idx + 1, len(sorted_blocks)):
            block = sorted_blocks[i]
            if block.get("type") == "bookmark":
                url = block.get("url", "")
                if "typescriptlang.org" in url.lower() or "mozilla.org" in url.lower():
                    bookmark_count += 1

        if bookmark_count < 2:
            errors.append(f"[X] Expected 2 bookmark blocks, found {bookmark_count}")
        else:
            checks_passed.append("[C] Bookmark blocks found")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_company_handbook_communication_guidelines(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Communication Guidelines section in Company Handbook."""
    errors: list[str] = []

    checks_passed = []

    # Find Company Handbook page
    try:
        page = _find_page_by_title(final_state_backend, "Company Handbook")
        if not page:
            errors.append("[X] Company Handbook page not found")
        else:
            checks_passed.append("[C] Company Handbook page found")
    
        page_id = page.get("_id")
        page_blocks = _get_blocks_for_page(final_state_backend, page_id)
        sorted_blocks = sorted(page_blocks, key=lambda b: b.get("order", 0))

        # Check for Communication Guidelines heading
        comm_heading = False
        comm_idx = None
        for i, block in enumerate(sorted_blocks):
            if block.get("type") in ["heading3", "heading_3"]:
                content = block.get("content", "")
                if "communication guidelines" in content.lower():
                    comm_heading = True
                    comm_idx = i
                    break

        if not comm_heading:
            errors.append("[X] heading_3 'Communication Guidelines' not found")
        else:
            checks_passed.append("[C] Communication Guidelines heading found")

        # Check for blue callout about official channels
        blue_callout = False
        for block in sorted_blocks:
            if block.get("type") == "callout":
                properties = block.get("properties", {})
                bg_color = properties.get("backgroundColor", block.get("backgroundColor", ""))
                icon = properties.get("icon", block.get("icon", ""))
                content = block.get("content", "").lower()
                if "blue" in bg_color.lower() if bg_color else False:
                    if "📱" in icon if icon else False:
                        if "official channels" in content:
                            blue_callout = True
                            break

        if not blue_callout:
            errors.append("[X] Blue callout with 📱 icon about official channels not found")
        else:
            checks_passed.append("[C] Blue callout found")

        # Check for 3 bullet points
        bullet_count = 0
        required_bullets = ["slack", "email", "zoom"]
        for block in sorted_blocks:
            if block.get("type") in ["bulletedList", "bulleted_list", "bulletedListItem", "bulleted_list_item"]:
                content = block.get("content", "").lower()
                for req in required_bullets:
                    if req in content:
                        bullet_count += 1
                        break

        if bullet_count < 3:
            errors.append(f"[X] Expected 3 bullet points about communication, found {bullet_count}")
        else:
            checks_passed.append("[C] 3 bullet points found")

        # Check for divider after bullets
        divider_found = False
        if comm_idx is not None:
            for block in sorted_blocks[comm_idx:]:
                if block.get("type") == "divider":
                    divider_found = True
                    break

        if not divider_found:
            errors.append("[X] Divider after Communication Guidelines not found")
        else:
            checks_passed.append("[C] Divider found")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_create_engineering_documentation_hub(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Engineering Documentation Hub under Engineering Wiki."""
    errors: list[str] = []

    checks_passed = []

    # Find Engineering Wiki page
    try:
        wiki_page = _find_page_by_title(final_state_backend, "Engineering Wiki")
        if not wiki_page:
            errors.append("[X] Engineering Wiki page not found")
        else:
            checks_passed.append("[C] Engineering Wiki page found")
    
        # Find Engineering Documentation Hub page
        hub_page = _find_page_by_title(final_state_backend, "Engineering Documentation Hub")
        if not hub_page:
            errors.append("[X] Engineering Documentation Hub page not found")
        else:
            checks_passed.append("[C] Engineering Documentation Hub page found")
    
        # Check parent relationship
        if hub_page.get("parentId") != wiki_page.get("_id"):
            errors.append("[X] Documentation Hub should be under Engineering Wiki")
        else:
            checks_passed.append("[C] Page under Engineering Wiki")

        page_id = hub_page.get("_id")
        page_blocks = _get_blocks_for_page(final_state_backend, page_id)
        sorted_blocks = sorted(page_blocks, key=lambda b: b.get("order", 0))

        # Check for heading_1
        main_heading = False
        for block in sorted_blocks:
            if block.get("type") in ["heading1", "heading_1"]:
                content = block.get("content", "")
                if "🔧" in content and "engineering documentation hub" in content.lower():
                    main_heading = True
                    break

        if not main_heading:
            errors.append("[X] heading_1 '🔧 Engineering Documentation Hub' not found")
        else:
            checks_passed.append("[C] Main heading found")

        # Check for Overview section
        overview = False
        for block in sorted_blocks:
            if block.get("type") in ["heading2", "heading_2"]:
                content = block.get("content", "")
                if "📚" in content and "overview" in content.lower():
                    overview = True
                    break

        if not overview:
            errors.append("[X] heading_2 '📚 Overview' not found")
        else:
            checks_passed.append("[C] Overview section found")

        # Check for Architecture Documents section
        architecture = False
        for block in sorted_blocks:
            if block.get("type") in ["heading2", "heading_2"]:
                content = block.get("content", "")
                if "🏗️" in content and "architecture" in content.lower():
                    architecture = True
                    break

        if not architecture:
            errors.append("[X] heading_2 '🏗️ Architecture Documents' not found")
        else:
            checks_passed.append("[C] Architecture Documents section found")

        # Check for bookmark blocks
        bookmark_count = 0
        for block in sorted_blocks:
            if block.get("type") == "bookmark":
                properties = block.get("properties", {})
                url = properties.get("url", block.get("url", ""))
                if "notion.so" in url:
                    bookmark_count += 1

        if bookmark_count < 2:
            errors.append(f"[X] Expected 2 bookmark blocks, found {bookmark_count}")
        else:
            checks_passed.append("[C] Bookmark blocks found")

        # Check for Quick Links section
        quick_links = False
        for block in sorted_blocks:
            if block.get("type") in ["heading2", "heading_2"]:
                content = block.get("content", "")
                if "🔗" in content and "quick links" in content.lower():
                    quick_links = True
                    break

        if not quick_links:
            errors.append("[X] heading_2 '🔗 Quick Links' not found")
        else:
            checks_passed.append("[C] Quick Links section found")

        # Check for numbered list items
        numbered_items = 0
        for block in sorted_blocks:
            if block.get("type") in ["numberedList", "numbered_list", "numberedListItem", "numbered_list_item"]:
                numbered_items += 1

        if numbered_items < 3:
            errors.append(f"[X] Expected 3 numbered list items, found {numbered_items}")
        else:
            checks_passed.append("[C] Numbered list items found")

        # Check for gray security callout
        security_callout = False
        for block in sorted_blocks:
            if block.get("type") == "callout":
                properties = block.get("properties", {})
                bg_color = properties.get("backgroundColor", block.get("backgroundColor", ""))
                icon = properties.get("icon", block.get("icon", ""))
                content = block.get("content", "").lower()
                if "gray" in bg_color.lower() if bg_color else False:
                    if "🔒" in icon if icon else False:
                        if "engineering team access" in content:
                            security_callout = True
                            break

        if not security_callout:
            errors.append("[X] Gray security callout not found")
        else:
            checks_passed.append("[C] Security callout found")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_create_japan_travel_planner(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Japan Travel Planner page with city sections and todos."""
    errors: list[str] = []

    checks_passed = []

    # Find Japan Travel Planner page
    try:
        page = _find_page_by_title(final_state_backend, "Japan Travel Planner")
        if not page:
            errors.append("[X] Japan Travel Planner 2024 page not found")
        else:
            checks_passed.append("[C] Japan Travel Planner 2024 page found")
    
        # Check page is at root level (no parentId)
        if page.get("parentId"):
            errors.append("[X] Page should be at root level (no parentId)")
        else:
            checks_passed.append("[C] Page at root level")

        page_id = page.get("_id")
        page_blocks = _get_blocks_for_page(final_state_backend, page_id)
        sorted_blocks = sorted(page_blocks, key=lambda b: b.get("order", 0))

        # Check for heading_1 with emoji
        main_heading = False
        for block in sorted_blocks:
            if block.get("type") in ["heading1", "heading_1"]:
                content = block.get("content", "")
                if "🗾" in content and "japan travel planner" in content.lower():
                    main_heading = True
                    break

        if not main_heading:
            errors.append("[X] heading_1 '🗾 Japan Travel Planner 2024' not found")
        else:
            checks_passed.append("[C] Main heading found")

        # Check for image with unsplash URL
        image_found = False
        for block in sorted_blocks:
            if block.get("type") == "image":
                properties = block.get("properties", {})
                url = properties.get("url", block.get("url", ""))
                caption = properties.get("caption", block.get("caption", ""))
                if "unsplash" in url:
                    if "mount fuji" in caption.lower() or "fuji" in caption.lower():
                        image_found = True
                        break

        if not image_found:
            errors.append("[X] Image with Mount Fuji caption not found")
        else:
            checks_passed.append("[C] Mount Fuji image found")

        # Check for Trip Overview section
        trip_overview = False
        for block in sorted_blocks:
            if block.get("type") in ["heading2", "heading_2"]:
                content = block.get("content", "")
                if "📅" in content and "trip overview" in content.lower():
                    trip_overview = True
                    break

        if not trip_overview:
            errors.append("[X] heading_2 '📅 Trip Overview' not found")
        else:
            checks_passed.append("[C] Trip Overview section found")

        # Check for orange callout about trip
        trip_callout = False
        for block in sorted_blocks:
            if block.get("type") == "callout":
                properties = block.get("properties", {})
                bg_color = properties.get("backgroundColor", block.get("backgroundColor", ""))
                icon = properties.get("icon", block.get("icon", ""))
                content = block.get("content", "").lower()
                if "orange" in bg_color.lower() if bg_color else False:
                    if "📍" in icon if icon else False:
                        if "10-day" in content and "tokyo" in content:
                            trip_callout = True
                            break

        if not trip_callout:
            errors.append("[X] Orange callout about 10-day adventure not found")
        else:
            checks_passed.append("[C] Trip overview callout found")

        # Check for city headings
        cities = {"tokyo": False, "kyoto": False, "osaka": False}
        for block in sorted_blocks:
            if block.get("type") in ["heading3", "heading_3"]:
                content = block.get("content", "").lower()
                if "tokyo" in content:
                    cities["tokyo"] = True
                elif "kyoto" in content:
                    cities["kyoto"] = True
                elif "osaka" in content:
                    cities["osaka"] = True

        for city, found in cities.items():
            if not found:
                errors.append(f"[X] heading_3 for {city.title()} not found")
            else:
                checks_passed.append("[C] All 3 city headings found")

        # Check for 6 unchecked todos
        todo_count = 0
        for block in sorted_blocks:
            if block.get("type") in ["todo", "to_do", "checkbox"]:
                is_checked = block.get("properties", {}).get("checked", False) or block.get("checked", False)
                if not is_checked:
                    todo_count += 1

        if todo_count < 6:
            errors.append(f"[X] Expected 6 unchecked todos, found {todo_count}")
        else:
            checks_passed.append(f"[C] {todo_count} todos found")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_create_online_resume(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Online Resume page creation with work history."""
    errors: list[str] = []

    checks_passed = []

    # Find Online Resume page
    try:
        page = _find_page_by_title(final_state_backend, "Online Resume")
        if not page:
            errors.append("[X] Online Resume page not found")
        else:
            checks_passed.append("[C] Online Resume page found")
    
        # Check for briefcase icon
        icon = page.get("icon", "")
        if "💼" not in icon:
            errors.append("[X] Page does not have 💼 icon")
        else:
            checks_passed.append("[C] Page has 💼 icon")

        page_id = page.get("_id")
        page_blocks = _get_blocks_for_page(final_state_backend, page_id)
        sorted_blocks = sorted(page_blocks, key=lambda b: b.get("order", 0))

        # Check for Professional Resume heading_1
        resume_heading = False
        for block in sorted_blocks:
            if block.get("type") in ["heading1", "heading_1"]:
                content = block.get("content", "")
                if "💼" in content and "professional resume" in content.lower():
                    resume_heading = True
                    break

        if not resume_heading:
            errors.append("[X] heading_1 '💼 Professional Resume' not found")
        else:
            checks_passed.append("[C] Professional Resume heading found")

        # Check for Professional Summary section
        summary_found = False
        for block in sorted_blocks:
            if block.get("type") in ["heading2", "heading_2"]:
                content = block.get("content", "")
                if "professional summary" in content.lower():
                    summary_found = True
                    break

        if not summary_found:
            errors.append("[X] Professional Summary section not found")
        else:
            checks_passed.append("[C] Professional Summary section found")

        # Check for Work History section
        work_history = False
        for block in sorted_blocks:
            if block.get("type") in ["heading2", "heading_2"]:
                content = block.get("content", "")
                if "work history" in content.lower():
                    work_history = True
                    break

        if not work_history:
            errors.append("[X] Work History section not found")
        else:
            checks_passed.append("[C] Work History section found")

        # Check for Tech Corp heading_3
        tech_corp = False
        for block in sorted_blocks:
            if block.get("type") in ["heading3", "heading_3"]:
                content = block.get("content", "")
                if "tech corp" in content.lower() and "🏢" in content:
                    tech_corp = True
                    break

        if not tech_corp:
            errors.append("[X] Tech Corp entry not found")
        else:
            checks_passed.append("[C] Tech Corp entry found")

        # Check for StartupXYZ heading_3
        startup = False
        for block in sorted_blocks:
            if block.get("type") in ["heading3", "heading_3"]:
                content = block.get("content", "")
                if "startupxyz" in content.lower() and "🏢" in content:
                    startup = True
                    break

        if not startup:
            errors.append("[X] StartupXYZ entry not found")
        else:
            checks_passed.append("[C] StartupXYZ entry found")

        # Check for image blocks
        image_count = sum(1 for b in sorted_blocks if b.get("type") == "image")
        if image_count < 2:
            errors.append(f"[X] Expected at least 2 image blocks, found {image_count}")
        else:
            checks_passed.append(f"[C] {image_count} image blocks found")

        # Check for Education section
        education = False
        for block in sorted_blocks:
            if block.get("type") in ["heading2", "heading_2"]:
                content = block.get("content", "")
                if "🎓" in content and "education" in content.lower():
                    education = True
                    break

        if not education:
            errors.append("[X] Education section not found")
        else:
            checks_passed.append("[C] Education section found")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_create_sprint_retrospective_dashboard_2(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Sprint Retrospective Dashboard under Meeting Notes."""
    errors: list[str] = []

    checks_passed = []

    # Find Meeting Notes page
    try:
        meeting_notes = _find_page_by_title(final_state_backend, "Meeting Notes")
        if not meeting_notes:
            errors.append("[X] Meeting Notes page not found")
        else:
            checks_passed.append("[C] Meeting Notes page found")
    
        # Find Sprint Retrospective Dashboard
        dashboard = _find_page_by_title(final_state_backend, "Sprint Retrospective Dashboard")
        if not dashboard:
            errors.append("[X] Sprint Retrospective Dashboard page not found")
        else:
            checks_passed.append("[C] Sprint Retrospective Dashboard page found")
    
        # Check parent relationship
        if dashboard.get("parentId") != meeting_notes.get("_id"):
            errors.append("[X] Dashboard should be under Meeting Notes")
        else:
            checks_passed.append("[C] Page under Meeting Notes")

        page_id = dashboard.get("_id")
        page_blocks = _get_blocks_for_page(final_state_backend, page_id)
        sorted_blocks = sorted(page_blocks, key=lambda b: b.get("order", 0))

        # Check for heading_1
        main_heading = False
        for block in sorted_blocks:
            if block.get("type") in ["heading1", "heading_1"]:
                content = block.get("content", "")
                if "🔄" in content and "sprint retrospective dashboard" in content.lower():
                    main_heading = True
                    break

        if not main_heading:
            errors.append("[X] heading_1 '🔄 Sprint Retrospective Dashboard' not found")
        else:
            checks_passed.append("[C] Main heading found")

        # Check for Meeting Analysis section
        meeting_analysis = False
        for block in sorted_blocks:
            if block.get("type") in ["heading2", "heading_2"]:
                content = block.get("content", "")
                if "📊" in content and "meeting analysis" in content.lower():
                    meeting_analysis = True
                    break

        if not meeting_analysis:
            errors.append("[X] heading_2 '📊 Meeting Analysis' not found")
        else:
            checks_passed.append("[C] Meeting Analysis section found")

        # Check for Team Retrospective Deep Dive heading
        deep_dive = False
        for block in sorted_blocks:
            if block.get("type") in ["heading3", "heading_3"]:
                content = block.get("content", "")
                if "🔍" in content and "team retrospective" in content.lower():
                    deep_dive = True
                    break

        if not deep_dive:
            errors.append("[X] heading_3 '🔍 Team Retrospective Deep Dive' not found")
        else:
            checks_passed.append("[C] Team Retrospective Deep Dive section found")

        # Check for divider
        divider_found = any(b.get("type") == "divider" for b in sorted_blocks)
        if not divider_found:
            errors.append("[X] Divider not found")
        else:
            checks_passed.append("[C] Divider found")

        # Check for Action Items section
        action_items = False
        for block in sorted_blocks:
            if block.get("type") in ["heading2", "heading_2"]:
                content = block.get("content", "")
                if "✨" in content and "action items" in content.lower():
                    action_items = True
                    break

        if not action_items:
            errors.append("[X] heading_2 '✨ Action Items' not found")
        else:
            checks_passed.append("[C] Action Items section found")

        # Check for 5 unchecked todos
        todo_count = 0
        for block in sorted_blocks:
            if block.get("type") in ["todo", "to_do", "checkbox"]:
                is_checked = block.get("properties", {}).get("checked", False) or block.get("checked", False)
                if not is_checked:
                    todo_count += 1

        if todo_count < 5:
            errors.append(f"[X] Expected 5 unchecked todos, found {todo_count}")
        else:
            checks_passed.append("[C] 5 action item todos found")

        # Check for orange callout
        orange_callout = False
        for block in sorted_blocks:
            if block.get("type") == "callout":
                properties = block.get("properties", {})
                bg_color = properties.get("backgroundColor", block.get("backgroundColor", ""))
                icon = properties.get("icon", block.get("icon", ""))
                content = block.get("content", "").lower()
                if "orange" in bg_color.lower() if bg_color else False:
                    if "📌" in icon if icon else False:
                        if "continuous improvement" in content:
                            orange_callout = True
                            break

        if not orange_callout:
            errors.append("[X] Orange callout about continuous improvement not found")
        else:
            checks_passed.append("[C] Orange callout found")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_create_team_task_tracker_2(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate team task tracker with workspace-wide todo analysis."""
    errors: list[str] = []

    checks_passed = []

    # Find Team Task Tracker page
    try:
        page = _find_page_by_title(final_state_backend, "Team Task Tracker")
        if not page:
            errors.append("[X] Team Task Tracker page not found")
        else:
            checks_passed.append("[C] Team Task Tracker page found")
    
        # Check page is at root level
        if page.get("parentId"):
            errors.append("[X] Team Task Tracker should be at root level")
        else:
            checks_passed.append("[C] Page at root level")

        page_id = page.get("_id")
        page_blocks = _get_blocks_for_page(final_state_backend, page_id)
        sorted_blocks = sorted(page_blocks, key=lambda b: b.get("order", 0))

        # Check for heading_1
        main_heading = False
        for block in sorted_blocks:
            if block.get("type") in ["heading1", "heading_1"]:
                content = block.get("content", "")
                if "📋" in content and "team task tracker" in content.lower():
                    main_heading = True
                    break

        if not main_heading:
            errors.append("[X] heading_1 '📋 Team Task Tracker' not found")
        else:
            checks_passed.append("[C] Main heading found")

        # Check for Generated heading
        generated = False
        for block in sorted_blocks:
            if block.get("type") in ["heading2", "heading_2"]:
                content = block.get("content", "")
                if "🕐" in content and "generated" in content.lower():
                    generated = True
                    break

        if not generated:
            errors.append("[X] heading_2 '🕐 Generated' not found")
        else:
            checks_passed.append("[C] Generated heading found")

        # Check for Summary Dashboard heading
        dashboard = False
        for block in sorted_blocks:
            if block.get("type") in ["heading2", "heading_2"]:
                content = block.get("content", "")
                if "📊" in content and "summary dashboard" in content.lower():
                    dashboard = True
                    break

        if not dashboard:
            errors.append("[X] heading_2 '📊 Summary Dashboard' not found")
        else:
            checks_passed.append("[C] Summary Dashboard heading found")

        # Check for red callout with task summary
        summary_callout = False
        for block in sorted_blocks:
            if block.get("type") == "callout":
                properties = block.get("properties", {})
                bg_color = properties.get("backgroundColor", block.get("backgroundColor", ""))
                icon = properties.get("icon", block.get("icon", ""))
                content = block.get("content", "").lower()
                if "red" in bg_color.lower() if bg_color else False:
                    if "🚨" in icon if icon else False:
                        if "total workspace tasks" in content:
                            summary_callout = True
                            break

        if not summary_callout:
            errors.append("[X] Red callout with task summary not found")
        else:
            checks_passed.append("[C] Task summary callout found")

        # Check for page section headings (heading_3)
        page_sections = 0
        for block in sorted_blocks:
            if block.get("type") in ["heading3", "heading_3"]:
                content = block.get("content", "")
                if "📄" in content:
                    page_sections += 1

        if page_sections < 3:
            errors.append(f"[X] Expected at least 3 page sections, found {page_sections}")
        else:
            checks_passed.append(f"[C] {page_sections} page sections found")

        # Check for Priority Actions heading
        priority = False
        for block in sorted_blocks:
            if block.get("type") in ["heading2", "heading_2"]:
                content = block.get("content", "")
                if "🎯" in content and "priority actions" in content.lower():
                    priority = True
                    break

        if not priority:
            errors.append("[X] heading_2 '🎯 Priority Actions' not found")
        else:
            checks_passed.append("[C] Priority Actions heading found")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_design_system_color_documentation(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Design System color documentation addition."""
    errors: list[str] = []

    checks_passed = []

    # Find Design System page
    try:
        page = _find_page_by_title(final_state_backend, "Design System")
        if not page:
            errors.append("[X] Design System page not found")
        else:
            checks_passed.append("[C] Design System page found")

        page_id = page.get("_id")
        page_blocks = _get_blocks_for_page(final_state_backend, page_id)
        sorted_blocks = sorted(page_blocks, key=lambda b: b.get("order", 0))

        # Check for heading_3 '🎨 Primary Colors'
        primary_heading_found = False
        for block in sorted_blocks:
            if block.get("type") in ["heading3", "heading_3"]:
                content = block.get("content", "")
                if "🎨" in content and "primary colors" in content.lower():
                    primary_heading_found = True
                    break

        if not primary_heading_found:
            errors.append("[X] heading_3 '🎨 Primary Colors' not found")
        else:
            checks_passed.append("[C] Primary Colors heading found")

        # Check for gray callout about CTAs
        gray_callout_found = False
        for block in sorted_blocks:
            if block.get("type") == "callout":
                properties = block.get("properties", {})
                bg_color = properties.get("backgroundColor", block.get("backgroundColor", ""))
                content = block.get("content", "").lower()
                if bg_color and "gray" in bg_color.lower():
                    if "cta" in content or "brand identity" in content:
                        gray_callout_found = True
                        break

        if not gray_callout_found:
            errors.append("[X] Gray callout about CTAs/brand identity not found")
        else:
            checks_passed.append("[C] Primary colors callout found")

        # Check for 3 CSS code blocks with color values
        css_code_blocks = 0
        required_colors = ["#0066cc", "#0052a3", "#3385e0"]
    
        for block in sorted_blocks:
            if block.get("type") == "code":
                content = block.get("content", "").lower()
                properties = block.get("properties", {})
                language = properties.get("language", block.get("language", ""))
                if "css" in language.lower() or any(color in content for color in required_colors):
                    css_code_blocks += 1

        if css_code_blocks < 3:
            errors.append(f"[X] Expected 3 CSS code blocks, found {css_code_blocks}")
        else:
            checks_passed.append("[C] 3 CSS code blocks found")

        # Check for heading_3 '🌈 Semantic Colors'
        semantic_heading_found = False
        for block in sorted_blocks:
            if block.get("type") in ["heading3", "heading_3"]:
                content = block.get("content", "")
                if "🌈" in content and "semantic colors" in content.lower():
                    semantic_heading_found = True
                    break

        if not semantic_heading_found:
            errors.append("[X] heading_3 '🌈 Semantic Colors' not found")
        else:
            checks_passed.append("[C] Semantic Colors heading found")

        # Check for 3 bulleted list items with color hex codes
        semantic_bullets = 0
        required_semantic = ["success", "warning", "error"]
    
        for block in sorted_blocks:
            if block.get("type") in ["bulletedList", "bulleted_list", "bulletedListItem", "bulleted_list_item"]:
                content = block.get("content", "").lower()
                for keyword in required_semantic:
                    if keyword in content and "#" in content:
                        semantic_bullets += 1
                        break

        if semantic_bullets < 3:
            errors.append(f"[X] Expected 3 semantic color bullets, found {semantic_bullets}")
        else:
            checks_passed.append("[C] 3 semantic color bullets found")

        # Check for bookmark with design URL
        bookmark_found = False
        for block in sorted_blocks:
            if block.get("type") == "bookmark":
                properties = block.get("properties", {})
                url = properties.get("url", block.get("url", ""))
                caption = properties.get("caption", block.get("caption", ""))
                if "design" in url.lower() or "color" in (caption or "").lower():
                    bookmark_found = True
                    break

        if not bookmark_found:
            errors.append("[X] Bookmark for color explorer not found")
        else:
            checks_passed.append("[C] Color explorer bookmark found")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_design_system_component_documentation(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate component documentation template implementation."""
    errors: list[str] = []

    checks_passed = []

    # Find Design System page
    try:
        page = _find_page_by_title(final_state_backend, "Design System")
        if not page:
            errors.append("[X] Design System page not found")
        else:
            checks_passed.append("[C] Design System page found")
    
        page_id = page.get("_id")
        page_blocks = _get_blocks_for_page(final_state_backend, page_id)
        sorted_blocks = sorted(page_blocks, key=lambda b: b.get("order", 0))

        # Check for Component Showcase headings
        showcase_count = 0
        for block in sorted_blocks:
            if block.get("type") in ["heading3", "heading_3"]:
                content = block.get("content", "")
                if "🎨" in content and "component showcase" in content.lower():
                    showcase_count += 1

        if showcase_count == 0:
            errors.append("[X] heading_3 '🎨 Component Showcase' not found")
        else:
            checks_passed.append(f"[C] {showcase_count} Component Showcase headings found")

        # Check for CSS code blocks
        css_code_count = 0
        for block in sorted_blocks:
            if block.get("type") == "code":
                properties = block.get("properties", {})
                language = properties.get("language", block.get("language", ""))
                if language.lower() == "css":
                    css_code_count += 1

        if css_code_count == 0:
            errors.append("[X] CSS code blocks not found")
        else:
            checks_passed.append(f"[C] {css_code_count} CSS code blocks found")

        # Check for Implementation Guide heading
        impl_guide = False
        for block in sorted_blocks:
            if block.get("type") in ["heading2", "heading_2"]:
                content = block.get("content", "")
                if "🔧" in content and "implementation guide" in content.lower():
                    impl_guide = True
                    break

        if not impl_guide:
            errors.append("[X] heading_2 '🔧 Implementation Guide' not found")
        else:
            checks_passed.append("[C] Implementation Guide heading found")

        # Check for numbered list with 3 items
        numbered_items = []
        for block in sorted_blocks:
            if block.get("type") in ["numberedList", "numbered_list", "numberedListItem", "numbered_list_item"]:
                content = block.get("content", "").lower()
                if any(x in content for x in ["import component", "apply base styling", "customize with theme"]):
                    numbered_items.append(content)

        if len(numbered_items) < 3:
            errors.append(f"[X] Expected 3 numbered list items, found {len(numbered_items)}")
        else:
            checks_passed.append("[C] 3 numbered list items found")

        # Check for gray callout
        gray_callout = False
        for block in sorted_blocks:
            if block.get("type") == "callout":
                properties = block.get("properties", {})
                bg_color = properties.get("backgroundColor", block.get("backgroundColor", ""))
                content = block.get("content", "").lower()
                if "gray" in bg_color.lower() if bg_color else False:
                    if "dark mode" in content:
                        gray_callout = True
                        break

        if not gray_callout:
            errors.append("[X] Gray callout about dark mode not found")
        else:
            checks_passed.append("[C] Gray callout found")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_design_system_component_library_overview(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Design System page with component library overview."""
    errors: list[str] = []

    checks_passed = []

    # Find Design System page
    try:
        design_system = _find_page_by_title(final_state_backend, "Design System")
        if not design_system:
            errors.append("[X] Design System page not found")
        else:
            checks_passed.append("[C] Design System page found")

        page_id = design_system.get("_id")
        page_blocks = _get_blocks_for_page(final_state_backend, page_id)
        sorted_blocks = sorted(page_blocks, key=lambda b: b.get("order", 0))
        checks_passed.append("[C] Design System page found")

        # Check for Component Library Overview heading
        overview_idx = None
        for i, block in enumerate(sorted_blocks):
            if block.get("type") in ["heading2", "heading_2"]:
                content = block.get("content", "")
                if "🗂️" in content and "component library overview" in content.lower():
                    overview_idx = i
                    break

        if overview_idx is None:
            errors.append("[X] heading_2 '🗂️ Component Library Overview' not found")
        else:
            checks_passed.append("[C] Component Library Overview heading found")

        # Get child pages
        child_pages = _get_child_pages(final_state_backend, page_id)
        if not child_pages:
            errors.append("[X] No child pages found under Design System")
        else:
            checks_passed.append("[C] child pages found under Design System")

        # Check for bookmark at the end
        bookmark_found = False
        for block in reversed(sorted_blocks):
            if block.get("type") == "bookmark":
                url = block.get("url", "")
                if "figma.com/design-systems" in url.lower():
                    bookmark_found = True
                    break

        if not bookmark_found:
            errors.append("[X] Figma bookmark not found at end")
        else:
            checks_passed.append("[C] Figma bookmark found")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_design_system_typography(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Typography Guidelines section on Design System page."""
    errors: list[str] = []

    checks_passed = []

    # Find Design System page
    try:
        design_system = _find_page_by_title(final_state_backend, "Design System")
        if not design_system:
            errors.append("[X] Design System page not found")
        else:
            checks_passed.append("[C] Design System page found")
    
        page_id = design_system.get("_id")
        page_blocks = _get_blocks_for_page(final_state_backend, page_id)
        sorted_blocks = sorted(page_blocks, key=lambda b: b.get("order", 0))
        checks_passed.append("[C] Design System page found")

        # Check 1: heading_2 'Typography Guidelines'
        typography_heading_found = False
        for block in sorted_blocks:
            if block.get("type") in ["heading2", "heading_2"]:
                content = block.get("content", "")
                if "typography guidelines" in content.lower():
                    typography_heading_found = True
                    break

        if not typography_heading_found:
            errors.append("[X] heading_2 'Typography Guidelines' not found")
        else:
            checks_passed.append("[C] Typography Guidelines heading_2 found")

        # Check 2: heading_3 '📝 Font Stack'
        font_stack_heading_found = False
        for block in sorted_blocks:
            if block.get("type") in ["heading3", "heading_3"]:
                content = block.get("content", "")
                if "📝" in content and "font stack" in content.lower():
                    font_stack_heading_found = True
                    break

        if not font_stack_heading_found:
            errors.append("[X] heading_3 '📝 Font Stack' not found")
        else:
            checks_passed.append("[C] Font Stack heading_3 found")

        # Check 3: CSS code block with font-family
        css_code_found = False
        for block in sorted_blocks:
            if block.get("type") == "code":
                properties = block.get("properties", {})
                language = properties.get("language", "")
                content = block.get("content", "")
            
                if language.lower() == "css" and "font-family" in content:
                    css_code_found = True
                    break

        if not css_code_found:
            errors.append("[X] CSS code block with font-family not found")
        else:
            checks_passed.append("[C] CSS font-family code block found")

        # Check 4: heading_3 '📏 Type Scale'
        type_scale_heading_found = False
        for block in sorted_blocks:
            if block.get("type") in ["heading3", "heading_3"]:
                content = block.get("content", "")
                if "📏" in content and "type scale" in content.lower():
                    type_scale_heading_found = True
                    break

        if not type_scale_heading_found:
            errors.append("[X] heading_3 '📏 Type Scale' not found")
        else:
            checks_passed.append("[C] Type Scale heading_3 found")

        # Check 5: Bulleted list items with rem/px values
        bulleted_items = [b for b in sorted_blocks if b.get("type") in ["bulletedList", "bulleted_list", "bulleted_list_item"]]
        rem_items = [b for b in bulleted_items if "rem" in b.get("content", "").lower()]
    
        if len(rem_items) < 5:
            errors.append(f"[X] Expected 5 type scale bulleted items with rem values, found {len(rem_items)}")
        else:
            checks_passed.append(f"[C] Found {len(rem_items)} type scale items")

        # Check 6: Purple callout with 🎨 icon
        purple_callout_found = False
        for block in sorted_blocks:
            if block.get("type") == "callout":
                properties = block.get("properties", {})
                bg_color = properties.get("backgroundColor", block.get("backgroundColor", ""))
                icon = properties.get("icon", block.get("icon", ""))
            
                has_purple_bg = "purple" in bg_color.lower() if bg_color else False
                has_palette_icon = "🎨" in icon if icon else False
            
                if has_purple_bg and has_palette_icon:
                    purple_callout_found = True
                    break

        if not purple_callout_found:
            errors.append("[X] Purple callout with 🎨 icon not found")
        else:
            checks_passed.append("[C] Purple typography callout found")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_documentation_index_complete_map(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Documentation Index page with complete map of all descendants."""
    errors: list[str] = []

    checks_passed = []

    # Find Project Documentation page
    try:
        project_doc = _find_page_by_title(final_state_backend, "Project Documentation")
        if not project_doc:
            errors.append("[X] Project Documentation page not found")
        else:
            checks_passed.append("[C] Project Documentation page found")

        # Find Documentation Index child page
        doc_index = _find_child_by_title(final_state_backend, project_doc, "Documentation Index")
        if not doc_index:
            errors.append("[X] Documentation Index page not found as child of Project Documentation")
        else:
            checks_passed.append("[C] Documentation Index page found as child of Project Documentation")

        page_id = doc_index.get("_id")
        page_blocks = _get_blocks_for_page(final_state_backend, page_id)
        sorted_blocks = sorted(page_blocks, key=lambda b: b.get("order", 0))
        checks_passed.append("[C] Documentation Index page found")

        # Check for heading_1 '🗂️ Complete Documentation Map'
        map_heading = None
        for block in sorted_blocks:
            if block.get("type") in ["heading1", "heading_1"]:
                content = block.get("content", "")
                if "🗂️" in content and "complete documentation map" in content.lower():
                    map_heading = block
                    break

        if not map_heading:
            errors.append("[X] heading_1 '🗂️ Complete Documentation Map' not found")
        else:
            checks_passed.append("[C] Complete Documentation Map heading found")

        # Check for Documentation Stats section
        stats_idx = None
        for i, block in enumerate(sorted_blocks):
            if block.get("type") in ["heading2", "heading_2"]:
                content = block.get("content", "")
                if "📊" in content and "documentation stats" in content.lower():
                    stats_idx = i
                    break

        if stats_idx is None:
            errors.append("[X] heading_2 '📊 Documentation Stats' not found")
        else:
            checks_passed.append("[C] Documentation Stats section found")

        # Check for blue callout with stats
        stats_callout = False
        for i in range(stats_idx + 1, min(stats_idx + 5, len(sorted_blocks))):
            block = sorted_blocks[i]
            if block.get("type") == "callout":
                properties = block.get("properties", {})
                bg_color = properties.get("backgroundColor", block.get("backgroundColor", ""))
                icon = properties.get("icon", block.get("icon", ""))
                content = block.get("content", "")
            
                if "blue" in bg_color.lower() if bg_color else False:
                    if "📈" in icon if icon else False:
                        if "total pages:" in content.lower() and "favorite pages:" in content.lower():
                            stats_callout = True
                            break

        if not stats_callout:
            errors.append("[X] Blue callout with 📈 icon and stats not found")
        else:
            checks_passed.append("[C] Stats callout found")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_engineering_wiki_security_tools(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Engineering Wiki Security Tools section addition."""
    errors: list[str] = []

    checks_passed = []

    # Find Engineering Wiki page
    try:
        page = _find_page_by_title(final_state_backend, "Engineering Wiki")
        if not page:
            errors.append("[X] Engineering Wiki page not found")
        else:
            checks_passed.append("[C] Engineering Wiki page found")

        page_id = page.get("_id")
        page_blocks = _get_blocks_for_page(final_state_backend, page_id)
        sorted_blocks = sorted(page_blocks, key=lambda b: b.get("order", 0))

        # Check for heading_3 '🔐 Security Tools'
        security_heading_found = False
        security_heading_order = -1
        for block in sorted_blocks:
            if block.get("type") in ["heading3", "heading_3"]:
                content = block.get("content", "")
                if "🔐" in content and "security tools" in content.lower():
                    security_heading_found = True
                    security_heading_order = block.get("order", 0)
                    break

        if not security_heading_found:
            errors.append("[X] heading_3 '🔐 Security Tools' not found")
        else:
            checks_passed.append("[C] Security Tools heading found")

        # Check for three bulleted list items with specific emojis
        security_bullets = []
        required_items = [
            ("🛡️", "sonarqube"),
            ("🔑", "hashicorp vault"),
            ("🚨", "snyk"),
        ]
    
        for block in sorted_blocks:
            if block.get("type") in ["bulletedList", "bulleted_list", "bulletedListItem", "bulleted_list_item"]:
                content = block.get("content", "")
                for emoji, keyword in required_items:
                    if emoji in content and keyword in content.lower():
                        security_bullets.append(keyword)

        if len(security_bullets) < 3:
            errors.append(f"[X] Expected 3 security tool bullet points, found {len(security_bullets)}")
        else:
            checks_passed.append("[C] 3 security tool bullets found")

        # Check for quote block with security text
        quote_found = False
        for block in sorted_blocks:
            if block.get("type") == "quote":
                content = block.get("content", "").lower()
                if "security is not a feature" in content and "fundamental requirement" in content:
                    quote_found = True
                    break

        if not quote_found:
            errors.append("[X] Quote block with security text not found")
        else:
            checks_passed.append("[C] Security quote found")

        # Check for bookmark block with OWASP URL
        bookmark_found = False
        for block in sorted_blocks:
            if block.get("type") == "bookmark":
                properties = block.get("properties", {})
                url = properties.get("url", block.get("url", ""))
                if "owasp.org" in url.lower():
                    bookmark_found = True
                    break

        if not bookmark_found:
            errors.append("[X] Bookmark with OWASP URL not found")
        else:
            checks_passed.append("[C] OWASP bookmark found")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_engineering_wiki_swap_and_enhance(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Engineering Wiki section swap and enhancements."""
    errors: list[str] = []

    checks_passed = []

    # Find Engineering Wiki page
    try:
        page = _find_page_by_title(final_state_backend, "Engineering Wiki")
        if not page:
            errors.append("[X] Engineering Wiki page not found")
        else:
            checks_passed.append("[C] Engineering Wiki page found")

        page_id = page.get("_id")
        page_blocks = _get_blocks_for_page(final_state_backend, page_id)
        sorted_blocks = sorted(page_blocks, key=lambda b: b.get("order", 0))

        # Find positions of Development Setup and Tech Stack headings
        dev_setup_order = -1
        tech_stack_order = -1
        env_vars_order = -1
    
        for block in sorted_blocks:
            if block.get("type") in ["heading2", "heading_2"]:
                content = block.get("content", "").lower()
                if "development setup" in content:
                    dev_setup_order = block.get("order", 0)
                elif "tech stack" in content:
                    tech_stack_order = block.get("order", 0)
                elif "environment variables" in content:
                    env_vars_order = block.get("order", 0)

        # Check that Development Setup comes before Tech Stack (swapped)
        if dev_setup_order < 0 or tech_stack_order < 0:
            errors.append("[X] Could not find Development Setup and/or Tech Stack headings")
        else:
            checks_passed.append("[C] Could find Development Setup and/or Tech Stack headings")
    
        if dev_setup_order >= tech_stack_order:
            errors.append("[X] Development Setup should appear before Tech Stack (sections not swapped)")
        else:
            checks_passed.append("[C] Sections swapped correctly")

        # Check for red callout with ⚠️ after Environment Variables
        red_callout_found = False
        for block in sorted_blocks:
            if block.get("type") == "callout":
                properties = block.get("properties", {})
                bg_color = properties.get("backgroundColor", block.get("backgroundColor", ""))
                icon = properties.get("icon", block.get("icon", ""))
                content = block.get("content", "").lower()
                if bg_color and "red" in bg_color.lower():
                    if "⚠️" in (icon or "") or "⚠️" in content:
                        if ".env" in content and "version control" in content:
                            red_callout_found = True
                            break

        if not red_callout_found:
            errors.append("[X] Red callout with ⚠️ and .env warning not found")
        else:
            checks_passed.append("[C] Red warning callout found")

        # Check for bookmark with stackshare.io
        bookmark_found = False
        for block in sorted_blocks:
            if block.get("type") == "bookmark":
                properties = block.get("properties", {})
                url = properties.get("url", block.get("url", ""))
                if "stackshare.io" in url.lower():
                    bookmark_found = True
                    break

        if not bookmark_found:
            errors.append("[X] Bookmark with stackshare.io URL not found")
        else:
            checks_passed.append("[C] Stackshare bookmark found")

        # Check for divider
        divider_found = any(b.get("type") == "divider" for b in sorted_blocks)
        if not divider_found:
            errors.append("[X] Divider not found at end")
        else:
            checks_passed.append("[C] Divider found")

        # Check for quote at end with documentation text
        quote_found = False
        for block in sorted_blocks:
            if block.get("type") == "quote":
                content = block.get("content", "").lower()
                if "good documentation" in content and "good code" in content:
                    quote_found = True
                    break

        if not quote_found:
            errors.append("[X] Quote about documentation not found")
        else:
            checks_passed.append("[C] Documentation quote found")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_engineering_wiki_swap_tech_setup(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate section swap and callout insertion in Engineering Wiki."""
    errors: list[str] = []

    checks_passed = []

    # Find Engineering Wiki page
    try:
        page = _find_page_by_title(final_state_backend, "Engineering Wiki")
        if not page:
            errors.append("[X] Engineering Wiki page not found")
        else:
            checks_passed.append("[C] Engineering Wiki page found")
    
        page_id = page.get("_id")
        page_blocks = _get_blocks_for_page(final_state_backend, page_id)
        sorted_blocks = sorted(page_blocks, key=lambda b: b.get("order", 0))

        # Find Development Setup and Tech Stack indices
        dev_setup_idx = None
        tech_stack_idx = None
    
        for i, block in enumerate(sorted_blocks):
            if block.get("type") in ["heading2", "heading_2"]:
                content = block.get("content", "").lower()
                if "development setup" in content:
                    dev_setup_idx = i
                elif "tech stack" in content:
                    tech_stack_idx = i

        if dev_setup_idx is None:
            errors.append("[X] Development Setup section not found")
        else:
            checks_passed.append("[C] Development Setup section found")
        if tech_stack_idx is None:
            errors.append("[X] Tech Stack section not found")
        else:
            checks_passed.append("[C] Tech Stack section found")
    
        # Check Development Setup comes before Tech Stack
        if dev_setup_idx > tech_stack_idx:
            errors.append("[X] Development Setup should appear before Tech Stack after swap")
        else:
            checks_passed.append("[C] Sections swapped correctly")

        # Check for blue callout after Development Setup heading
        callout_found = False
        for i in range(dev_setup_idx + 1, min(dev_setup_idx + 5, len(sorted_blocks))):
            block = sorted_blocks[i]
            if block.get("type") == "callout":
                properties = block.get("properties", {})
                bg_color = properties.get("backgroundColor", block.get("backgroundColor", ""))
                icon = properties.get("icon", block.get("icon", ""))
                content = block.get("content", "").lower()
                if "blue" in bg_color.lower() if bg_color else False:
                    if "📌" in icon if icon else False:
                        if "complete all setup steps" in content:
                            callout_found = True
                            break

        if not callout_found:
            errors.append("[X] Blue callout with 📌 icon not found after Development Setup")
        else:
            checks_passed.append("[C] Blue callout found")

        # Check for bookmark at end
        bookmark_found = False
        for block in sorted_blocks[-5:]:
            if block.get("type") == "bookmark":
                properties = block.get("properties", {})
                url = properties.get("url", block.get("url", ""))
                caption = properties.get("caption", block.get("caption", ""))
                if "github" in url.lower():
                    bookmark_found = True
                    break

        if not bookmark_found:
            errors.append("[X] Bookmark with GitHub URL not found at end")
        else:
            checks_passed.append("[C] GitHub bookmark found at end")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_external_resources_complete_reorganization(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate External Resources section reorganization with statistics."""
    errors: list[str] = []

    checks_passed = []

    # Find External Resources page
    try:
        page = _find_page_by_title(final_state_backend, "External Resources")
        if not page:
            errors.append("[X] External Resources page not found")
        else:
            checks_passed.append("[C] External Resources page found")
    
        page_id = page.get("_id")
        page_blocks = _get_blocks_for_page(final_state_backend, page_id)
        sorted_blocks = sorted(page_blocks, key=lambda b: b.get("order", 0))

        # Find section indices
        tools_idx = None
        docs_idx = None
        learning_idx = None
    
        for i, block in enumerate(sorted_blocks):
            if block.get("type") in ["heading2", "heading_2"]:
                content = block.get("content", "").lower()
                if "tools" in content:
                    tools_idx = i
                elif "documentation" in content:
                    docs_idx = i
                elif "learning" in content:
                    learning_idx = i

        # Check Tools appears first
        if tools_idx is None:
            errors.append("[X] Tools section not found")
        else:
            checks_passed.append("[C] Tools section found")
        if docs_idx is None:
            errors.append("[X] Documentation section not found")
        else:
            checks_passed.append("[C] Documentation section found")
        if learning_idx is None:
            errors.append("[X] Learning section not found")
        else:
            checks_passed.append("[C] Learning section found")
    
        if not (tools_idx < docs_idx < learning_idx):
            errors.append("[X] Sections not in correct order: Tools, Documentation, Learning")
        else:
            checks_passed.append("[C] Sections in correct order")

        # Check for yellow callout after Learning heading
        yellow_callout = False
        if learning_idx is not None:
            for i in range(learning_idx + 1, min(learning_idx + 5, len(sorted_blocks))):
                block = sorted_blocks[i]
                if block.get("type") == "callout":
                    properties = block.get("properties", {})
                    bg_color = properties.get("backgroundColor", block.get("backgroundColor", ""))
                    icon = properties.get("icon", block.get("icon", ""))
                    content = block.get("content", "").lower()
                    if "yellow" in bg_color.lower() if bg_color else False:
                        if "💡" in icon if icon else False:
                            if "pro tip" in content:
                                yellow_callout = True
                                break

        if not yellow_callout:
            errors.append("[X] Yellow callout with 💡 icon not found after Learning heading")
        else:
            checks_passed.append("[C] Yellow pro tip callout found")

        # Check for Resource Statistics section at end
        stats_section = False
        for block in sorted_blocks[-10:]:
            if block.get("type") in ["heading2", "heading_2"]:
                content = block.get("content", "")
                if "📊" in content and "resource statistics" in content.lower():
                    stats_section = True
                    break

        if not stats_section:
            errors.append("[X] heading_2 '📊 Resource Statistics' not found at end")
        else:
            checks_passed.append("[C] Resource Statistics section found")

        # Check for paragraph with bookmark count
        stats_paragraph = False
        for block in sorted_blocks[-5:]:
            if block.get("type") == "paragraph":
                content = block.get("content", "").lower()
                if "total bookmarked resources" in content:
                    stats_paragraph = True
                    break

        if not stats_paragraph:
            errors.append("[X] Paragraph with bookmark count not found")
        else:
            checks_passed.append("[C] Bookmark count paragraph found")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_feature_request_analytics(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Feature Request Analytics page with implementation status."""
    errors: list[str] = []

    checks_passed = []

    # Find Feature Request Analytics page (root level)
    try:
        analytics_page = _find_page_by_title(final_state_backend, "Feature Request Analytics")
        if not analytics_page:
            errors.append("[X] Feature Request Analytics page not found")
        else:
            checks_passed.append("[C] Feature Request Analytics page found")

        page_id = analytics_page.get("_id")
        page_blocks = _get_blocks_for_page(final_state_backend, page_id)
        sorted_blocks = sorted(page_blocks, key=lambda b: b.get("order", 0))
        checks_passed.append("[C] Feature Request Analytics page found")

        # Check for heading_1 '📊 Feature Request Analytics'
        main_heading = None
        for block in sorted_blocks:
            if block.get("type") in ["heading1", "heading_1"]:
                content = block.get("content", "")
                if "📊" in content and "feature request analytics" in content.lower():
                    main_heading = block
                    break

        if not main_heading:
            errors.append("[X] heading_1 '📊 Feature Request Analytics' not found")
        else:
            checks_passed.append("[C] Main heading found")

        # Check for Implementation Status section
        status_idx = None
        for i, block in enumerate(sorted_blocks):
            if block.get("type") in ["heading2", "heading_2"]:
                content = block.get("content", "")
                if "🎯" in content and "implementation status" in content.lower():
                    status_idx = i
                    break

        if status_idx is None:
            errors.append("[X] heading_2 '🎯 Implementation Status' not found")
        else:
            checks_passed.append("[C] Implementation Status section found")

        # Check for purple callout at end
        purple_callout = False
        for block in reversed(sorted_blocks):
            if block.get("type") == "callout":
                properties = block.get("properties", {})
                bg_color = properties.get("backgroundColor", block.get("backgroundColor", ""))
                content = block.get("content", "")
            
                if "purple" in bg_color.lower() if bg_color else False:
                    if "last analysis run:" in content.lower():
                        purple_callout = True
                        break

        if not purple_callout:
            errors.append("[X] Purple callout with date not found")
        else:
            checks_passed.append("[C] Purple callout found")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_feature_requests_prioritization_matrix(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Feature Requests page with prioritization matrix and submission guidelines."""
    errors: list[str] = []

    checks_passed = []

    # Find Feature Requests page
    try:
        feature_requests = _find_page_by_title(final_state_backend, "Feature Requests")
        if not feature_requests:
            errors.append("[X] Feature Requests page not found")
        else:
            checks_passed.append("[C] Feature Requests page found")

        page_id = feature_requests.get("_id")
        page_blocks = _get_blocks_for_page(final_state_backend, page_id)
        sorted_blocks = sorted(page_blocks, key=lambda b: b.get("order", 0))
        checks_passed.append("[C] Feature Requests page found")

        # Check for Prioritization Matrix heading at beginning
        matrix_idx = None
        for i, block in enumerate(sorted_blocks[:10]):  # Check first 10 blocks
            if block.get("type") in ["heading2", "heading_2"]:
                content = block.get("content", "")
                if "🎯" in content and "request prioritization matrix" in content.lower():
                    matrix_idx = i
                    break

        if matrix_idx is None:
            errors.append("[X] heading_2 '🎯 Request Prioritization Matrix' not found at beginning")
        else:
            checks_passed.append("[C] Prioritization Matrix heading found")

        # Check for 4 callouts with specific colors and icons
        yellow_callout = False
        orange_callout = False
        blue_callout = False
        gray_callout = False

        for i in range(matrix_idx + 1, min(matrix_idx + 15, len(sorted_blocks))):
            block = sorted_blocks[i]
            if block.get("type") in ["heading2", "heading_2", "heading3", "heading_3"]:
                break
        
            if block.get("type") == "callout":
                properties = block.get("properties", {})
                bg_color = properties.get("backgroundColor", block.get("backgroundColor", ""))
                icon = properties.get("icon", block.get("icon", ""))
                content = block.get("content", "").upper()
            
                if "yellow" in bg_color.lower() if bg_color else False:
                    if "⚡" in icon if icon else False:
                        if "HIGH IMPACT, LOW EFFORT" in content:
                            yellow_callout = True
                elif "orange" in bg_color.lower() if bg_color else False:
                    if "🔥" in icon if icon else False:
                        if "HIGH IMPACT, HIGH EFFORT" in content:
                            orange_callout = True
                elif "blue" in bg_color.lower() if bg_color else False:
                    if "💡" in icon if icon else False:
                        if "LOW IMPACT, LOW EFFORT" in content:
                            blue_callout = True
                elif "gray" in bg_color.lower() if bg_color else False:
                    if "🔍" in icon if icon else False:
                        if "LOW IMPACT, HIGH EFFORT" in content:
                            gray_callout = True

        if not yellow_callout:
            errors.append("[X] Yellow callout with ⚡ icon and High Impact, Low Effort not found")
        else:
            checks_passed.append("[C] Yellow callout found")
    
        if not orange_callout:
            errors.append("[X] Orange callout with 🔥 icon and High Impact, High Effort not found")
        else:
            checks_passed.append("[C] Orange callout found")
    
        if not blue_callout:
            errors.append("[X] Blue callout with 💡 icon and Low Impact, Low Effort not found")
        else:
            checks_passed.append("[C] Blue callout found")
    
        if not gray_callout:
            errors.append("[X] Gray callout with 🔍 icon and Low Impact, High Effort not found")
        else:
            checks_passed.append("[C] Gray callout found")

        # Check for Submission Guidelines section
        guidelines_idx = None
        for i, block in enumerate(sorted_blocks):
            if block.get("type") in ["heading3", "heading_3"]:
                content = block.get("content", "")
                if "📝" in content and "submission guidelines" in content.lower():
                    guidelines_idx = i
                    break

        if guidelines_idx is None:
            errors.append("[X] heading_3 '📝 Submission Guidelines' not found")
        else:
            checks_passed.append("[C] Submission Guidelines heading found")

        # Check for 3 unchecked todos at end
        todo_count = 0
        for block in reversed(sorted_blocks):
            if block.get("type") in ["todo", "to_do", "checkbox"]:
                is_checked = block.get("properties", {}).get("checked", False) or block.get("checked", False)
                if not is_checked:
                    todo_count += 1
            if todo_count >= 3:
                break

        if todo_count < 3:
            errors.append(f"[X] Expected 3 unchecked todos at end, found {todo_count}")
        else:
            checks_passed.append("[C] 3 unchecked todos found")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_feature_requests_priority_visualization(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Feature Requests page with priority visualization callouts."""
    errors: list[str] = []

    checks_passed = []

    # Find Feature Requests page
    try:
        feature_requests = _find_page_by_title(final_state_backend, "Feature Requests")
        if not feature_requests:
            errors.append("[X] Feature Requests page not found")
        else:
            checks_passed.append("[C] Feature Requests page found")

        page_id = feature_requests.get("_id")
        page_blocks = _get_blocks_for_page(final_state_backend, page_id)
        sorted_blocks = sorted(page_blocks, key=lambda b: b.get("order", 0))
        checks_passed.append("[C] Feature Requests page found")

        # Check for Priority Visualization heading
        viz_idx = None
        for i, block in enumerate(sorted_blocks):
            if block.get("type") in ["heading2", "heading_2"]:
                content = block.get("content", "")
                if "🎨" in content and "priority visualization" in content.lower():
                    viz_idx = i
                    break

        if viz_idx is None:
            errors.append("[X] heading_2 '🎨 Priority Visualization' not found")
        else:
            checks_passed.append("[C] Priority Visualization heading found")

        # Check for three callouts with specific colors and icons
        red_callout = False
        yellow_callout = False
        green_callout = False

        for i in range(viz_idx + 1, min(viz_idx + 10, len(sorted_blocks))):
            block = sorted_blocks[i]
            if block.get("type") in ["heading2", "heading_2", "heading3", "heading_3"]:
                break
        
            if block.get("type") == "callout":
                properties = block.get("properties", {})
                bg_color = properties.get("backgroundColor", block.get("backgroundColor", ""))
                icon = properties.get("icon", block.get("icon", ""))
                content = block.get("content", "").upper()
            
                if "red" in bg_color.lower() if bg_color else False:
                    if "🔴" in icon if icon else False:
                        if "HIGH PRIORITY:" in content:
                            red_callout = True
                elif "yellow" in bg_color.lower() if bg_color else False:
                    if "🟡" in icon if icon else False:
                        if "COMMUNITY VOTES:" in content:
                            yellow_callout = True
                elif "green" in bg_color.lower() if bg_color else False:
                    if "🟢" in icon if icon else False:
                        if "COMPLETED:" in content:
                            green_callout = True

        if not red_callout:
            errors.append("[X] Red callout with 🔴 icon and HIGH PRIORITY text not found")
        else:
            checks_passed.append("[C] Red callout found")
    
        if not yellow_callout:
            errors.append("[X] Yellow callout with 🟡 icon and COMMUNITY VOTES text not found")
        else:
            checks_passed.append("[C] Yellow callout found")
    
        if not green_callout:
            errors.append("[X] Green callout with 🟢 icon and COMPLETED text not found")
        else:
            checks_passed.append("[C] Green callout found")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_feature_requests_tracking_system(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Feature Requests page with tracking system."""
    errors: list[str] = []

    checks_passed = []

    # Find Feature Requests page
    try:
        feature_requests = _find_page_by_title(final_state_backend, "Feature Requests")
        if not feature_requests:
            errors.append("[X] Feature Requests page not found")
        else:
            checks_passed.append("[C] Feature Requests page found")

        page_id = feature_requests.get("_id")
        page_blocks = _get_blocks_for_page(final_state_backend, page_id)
        sorted_blocks = sorted(page_blocks, key=lambda b: b.get("order", 0))
        checks_passed.append("[C] Feature Requests page found")

        # Check for heading_1 '🎯 Feature Request Tracker' at top
        tracker_heading = None
        for i, block in enumerate(sorted_blocks[:5]):  # Check first 5 blocks
            if block.get("type") in ["heading1", "heading_1"]:
                content = block.get("content", "")
                if "🎯" in content and "feature request tracker" in content.lower():
                    tracker_heading = block
                    break

        if not tracker_heading:
            errors.append("[X] heading_1 '🎯 Feature Request Tracker' not found at top")
        else:
            checks_passed.append("[C] Feature Request Tracker heading found")

        # Check for Request Statistics section at end
        stats_idx = None
        for i, block in enumerate(sorted_blocks):
            if block.get("type") in ["heading2", "heading_2"]:
                content = block.get("content", "")
                if "📈" in content and "request statistics" in content.lower():
                    stats_idx = i
                    break

        if stats_idx is None:
            errors.append("[X] heading_2 '📈 Request Statistics' not found")
        else:
            checks_passed.append("[C] Request Statistics section found")

        # Check for quote block with statistics
        quote_found = False
        for i in range(stats_idx + 1, min(stats_idx + 5, len(sorted_blocks))):
            block = sorted_blocks[i]
            if block.get("type") == "quote":
                content = block.get("content", "")
                if "total feature requests:" in content.lower() and "completion rate:" in content.lower():
                    quote_found = True
                    break

        if not quote_found:
            errors.append("[X] Quote block with statistics not found")
        else:
            checks_passed.append("[C] Quote block with statistics found")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_meeting_notes_index_system(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Meeting Notes page with index system for all child pages."""
    errors: list[str] = []

    checks_passed = []

    # Find Meeting Notes page
    try:
        meeting_notes = _find_page_by_title(final_state_backend, "Meeting Notes")
        if not meeting_notes:
            errors.append("[X] Meeting Notes page not found")
        else:
            checks_passed.append("[C] Meeting Notes page found")

        page_id = meeting_notes.get("_id")
        page_blocks = _get_blocks_for_page(final_state_backend, page_id)
        sorted_blocks = sorted(page_blocks, key=lambda b: b.get("order", 0))
        checks_passed.append("[C] Meeting Notes page found")

        # Check for heading_2 '📅 Meeting Index'
        meeting_index_idx = None
        for i, block in enumerate(sorted_blocks):
            if block.get("type") in ["heading2", "heading_2"]:
                content = block.get("content", "")
                if "📅" in content and "meeting index" in content.lower():
                    meeting_index_idx = i
                    break

        if meeting_index_idx is None:
            errors.append("[X] heading_2 '📅 Meeting Index' not found")
        else:
            checks_passed.append("[C] Meeting Index heading found")

        # Get child pages
        child_pages = _get_child_pages(final_state_backend, page_id)
        if not child_pages:
            errors.append("[X] No child pages found under Meeting Notes")
        else:
            checks_passed.append("[C] child pages found under Meeting Notes")

        # Check that each child page has an entry with heading_3, callout, and stats
        for child_page in child_pages:
            child_title = child_page.get("title", "")
            child_icon = child_page.get("icon", "")
        
            # Find heading_3 with icon and title
            found_heading = False
            found_callout = False
            found_stats = False
        
            for i in range(meeting_index_idx + 1, len(sorted_blocks)):
                block = sorted_blocks[i]
                if block.get("type") in ["heading2", "heading_2"]:
                    content = block.get("content", "")
                    if "📊" in content and "meeting statistics" in content.lower():
                        break
            
                if block.get("type") in ["heading3", "heading_3"]:
                    content = block.get("content", "")
                    if child_icon in content and child_title.lower() in content.lower():
                        found_heading = True
                        # Check for blue callout after heading
                        for j in range(i + 1, min(i + 5, len(sorted_blocks))):
                            next_block = sorted_blocks[j]
                            if next_block.get("type") == "callout":
                                properties = next_block.get("properties", {})
                                bg_color = properties.get("backgroundColor", next_block.get("backgroundColor", ""))
                                icon = properties.get("icon", next_block.get("icon", ""))
                                content_text = next_block.get("content", "")
                            
                                if "blue" in bg_color.lower() if bg_color else False:
                                    if child_icon in icon if icon else False:
                                        if "date:" in content_text.lower():
                                            found_callout = True
                                            # Check for stats paragraphs
                                            for k in range(j + 1, min(j + 5, len(sorted_blocks))):
                                                stat_block = sorted_blocks[k]
                                                if stat_block.get("type") == "paragraph":
                                                    stat_content = stat_block.get("content", "").lower()
                                                    if "key topics:" in stat_content or "action items:" in stat_content:
                                                        found_stats = True
                                                        break
                                            break
                        break

            if not found_heading:
                errors.append(f"[X] Entry for child page '{child_title}' not found with heading_3")
            else:
                checks_passed.append(f"[C] Entry for child page '{child_title}' found with heading_3")
            if not found_callout:
                errors.append(f"[X] Blue callout with date not found for '{child_title}'")
            else:
                checks_passed.append(f"[C] Blue callout with date found for '{child_title}'")
            if not found_stats:
                errors.append(f"[X] Stats paragraphs not found for '{child_title}'")
            else:
                checks_passed.append(f"[C] Stats paragraphs found for '{child_title}'")

        checks_passed.append(f"[C] All {len(child_pages)} child pages have entries")

        # Check for Meeting Statistics section
        stats_idx = None
        for i, block in enumerate(sorted_blocks):
            if block.get("type") in ["heading2", "heading_2"]:
                content = block.get("content", "")
                if "📊" in content and "meeting statistics" in content.lower():
                    stats_idx = i
                    break

        if stats_idx is None:
            errors.append("[X] heading_2 '📊 Meeting Statistics' not found")
        else:
            checks_passed.append("[C] Meeting Statistics section found")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_onboarding_guide_30_day_milestones(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Onboarding Guide page with 30-Day Milestones section."""
    errors: list[str] = []

    checks_passed = []

    # Find Onboarding Guide page
    try:
        onboarding = _find_page_by_title(final_state_backend, "Onboarding Guide")
        if not onboarding:
            errors.append("[X] Onboarding Guide page not found")
        else:
            checks_passed.append("[C] Onboarding Guide page found")

        page_id = onboarding.get("_id")
        page_blocks = _get_blocks_for_page(final_state_backend, page_id)
        sorted_blocks = sorted(page_blocks, key=lambda b: b.get("order", 0))
        checks_passed.append("[C] Onboarding Guide page found")

        # Find First Week Goals section
        first_week_idx = None
        for i, block in enumerate(sorted_blocks):
            if block.get("type") in ["heading2", "heading_2"]:
                content = block.get("content", "")
                if "first week goals" in content.lower():
                    first_week_idx = i
                    break

        if first_week_idx is None:
            errors.append("[X] First Week Goals section not found")
        else:
            checks_passed.append("[C] First Week Goals section found")

        # Check for 30-Day Milestones heading after First Week Goals
        milestones_idx = None
        for i in range(first_week_idx + 1, len(sorted_blocks)):
            block = sorted_blocks[i]
            if block.get("type") in ["heading2", "heading_2"]:
                content = block.get("content", "")
                if "🏆" in content and "30-day milestones" in content.lower():
                    milestones_idx = i
                    break
            # Stop if we hit a quote or divider before finding milestones
            if block.get("type") in ["quote", "divider"]:
                break

        if milestones_idx is None:
            errors.append("[X] heading_2 '🏆 30-Day Milestones' not found after First Week Goals")
        else:
            checks_passed.append("[C] 30-Day Milestones heading found")

        # Check for blue callout with 📌 icon
        callout_found = False
        for i in range(milestones_idx + 1, min(milestones_idx + 5, len(sorted_blocks))):
            block = sorted_blocks[i]
            if block.get("type") == "callout":
                properties = block.get("properties", {})
                bg_color = properties.get("backgroundColor", block.get("backgroundColor", ""))
                icon = properties.get("icon", block.get("icon", ""))
                content = block.get("content", "")
            
                if "blue" in bg_color.lower() if bg_color else False:
                    if "📌" in icon if icon else False:
                        if "complete these milestones" in content.lower():
                            callout_found = True
                            break

        if not callout_found:
            errors.append("[X] Blue callout with 📌 icon not found")
        else:
            checks_passed.append("[C] Blue callout with 📌 icon found")

        # Check for numbered list with 5 items
        numbered_list_found = False
        list_item_count = 0
        for i in range(milestones_idx + 1, min(milestones_idx + 10, len(sorted_blocks))):
            block = sorted_blocks[i]
            if block.get("type") in ["numberedList", "numbered_list"]:
                numbered_list_found = True
                # Count items in the list
                content = block.get("content", "")
                if content:
                    list_item_count = content.count("\n") + 1
                break

        if not numbered_list_found:
            errors.append("[X] Numbered list not found")
        else:
            checks_passed.append("[C] Numbered list found")
        if list_item_count < 5:
            errors.append(f"[X] Expected at least 5 items in numbered list, found {list_item_count}")
        else:
            checks_passed.append("[C] Numbered list with 5 items found")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_prd_swap_overview_user_stories(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate PRD section swap and metadata addition."""
    errors: list[str] = []

    checks_passed = []

    # Find Comprehensive PRD page
    try:
        page = _find_page_by_title(final_state_backend, "Comprehensive Product Requirements")
        if not page:
            errors.append("[X] Comprehensive Product Requirements Document page not found")
        else:
            checks_passed.append("[C] Comprehensive Product Requirements Document page found")
    
        page_id = page.get("_id")
        page_blocks = _get_blocks_for_page(final_state_backend, page_id)
        sorted_blocks = sorted(page_blocks, key=lambda b: b.get("order", 0))

        # Find Overview and User Stories section indices
        overview_idx = None
        user_stories_idx = None
    
        for i, block in enumerate(sorted_blocks):
            if block.get("type") in ["heading2", "heading_2"]:
                content = block.get("content", "").lower()
                if "overview" in content and overview_idx is None:
                    overview_idx = i
                elif "user stories" in content and user_stories_idx is None:
                    user_stories_idx = i

        if user_stories_idx is None:
            errors.append("[X] User Stories section not found")
        else:
            checks_passed.append("[C] User Stories section found")
    
        if overview_idx is None:
            errors.append("[X] Overview section not found")
        else:
            checks_passed.append("[C] Overview section found")
    
        # Check that User Stories appears before Overview (after swap)
        if user_stories_idx > overview_idx:
            errors.append("[X] User Stories should appear before Overview after swap")
        else:
            checks_passed.append("[C] Sections swapped correctly")

        # Check for orange callout with stakeholder review
        callout_found = False
        for block in sorted_blocks:
            if block.get("type") == "callout":
                properties = block.get("properties", {})
                bg_color = properties.get("backgroundColor", block.get("backgroundColor", ""))
                icon = properties.get("icon", block.get("icon", ""))
                content = block.get("content", "").lower()
                if "orange" in bg_color.lower() if bg_color else False:
                    if "🔍" in icon if icon else False:
                        if "stakeholder review" in content:
                            callout_found = True
                            break

        if not callout_found:
            errors.append("[X] Orange callout with stakeholder review note not found")
        else:
            checks_passed.append("[C] Stakeholder review callout found")

        # Check for Document Metadata heading at end
        metadata_found = False
        for block in sorted_blocks[-10:]:
            if block.get("type") in ["heading2", "heading_2"]:
                content = block.get("content", "")
                if "📎" in content and "document metadata" in content.lower():
                    metadata_found = True
                    break

        if not metadata_found:
            errors.append("[X] heading_2 '📎 Document Metadata' not found at end")
        else:
            checks_passed.append("[C] Document Metadata section found")

        # Check for timestamp paragraph
        timestamp_found = False
        for block in sorted_blocks[-5:]:
            if block.get("type") == "paragraph":
                content = block.get("content", "").lower()
                if "reorganized" in content:
                    timestamp_found = True
                    break

        if not timestamp_found:
            errors.append("[X] Timestamp paragraph not found")
        else:
            checks_passed.append("[C] Timestamp paragraph found")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_prd_technical_specifications_3(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate PRD with Technical Specifications section and swapped Part 2/Part 3 content."""
    errors: list[str] = []

    checks_passed = []

    # Find PRD page
    try:
        prd = _find_page_by_title(final_state_backend, "Comprehensive Product Requirements Document")
        if not prd:
            prd = _find_page_by_title(final_state_backend, "Product Requirements Document")
        if not prd:
            errors.append("[X] Product Requirements Document page not found")
        else:
            checks_passed.append("[C] Product Requirements Document page found")

        page_id = prd.get("_id")
        page_blocks = _get_blocks_for_page(final_state_backend, page_id)
        sorted_blocks = sorted(page_blocks, key=lambda b: b.get("order", 0))
        checks_passed.append("[C] Product Requirements Document page found")

        # Check 1: heading_3 '🔍 Technical Specifications'
        tech_spec_found = False
        tech_spec_idx = None
        for i, block in enumerate(sorted_blocks):
            if block.get("type") in ["heading3", "heading_3"]:
                content = block.get("content", "")
                if "🔍" in content and "technical specifications" in content.lower():
                    tech_spec_found = True
                    tech_spec_idx = i
                    break

        if not tech_spec_found:
            errors.append("[X] heading_3 '🔍 Technical Specifications' not found")
        else:
            checks_passed.append("[C] Technical Specifications heading_3 found")

        # Check 2: Three paragraphs with performance metrics
        metric_count = 0
        expected_metrics = ["page load time", "memory usage", "api response"]
    
        for block in sorted_blocks:
            if block.get("type") in ["paragraph", "text"]:
                content = block.get("content", "").lower()
                for metric in expected_metrics:
                    if metric in content:
                        metric_count += 1
                        break

        if metric_count < 3:
            errors.append(f"[X] Expected 3 performance metric paragraphs, found {metric_count}")
        else:
            checks_passed.append("[C] Performance metric paragraphs found")

        # Check 3: Part headings exist
        part_headings = []
        for i, block in enumerate(sorted_blocks):
            if block.get("type") in ["heading3", "heading_3"]:
                content = block.get("content", "").lower()
                if "overview - part" in content:
                    part_headings.append((i, content))

        if len(part_headings) < 3:
            errors.append(f"[X] Expected 3 Overview Part headings, found {len(part_headings)}")
        else:
            checks_passed.append(f"[C] Found {len(part_headings)} Overview Part headings")

        # Swap verification would require knowing original content
        checks_passed.append("[C] Part sections found - swap verification requires content analysis")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_product_specs_requirements_traceability(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Product Specs requirements traceability section."""
    errors: list[str] = []

    checks_passed = []

    # Find Product Specs page
    try:
        page = _find_page_by_title(final_state_backend, "Product Specs")
        if not page:
            errors.append("[X] Product Specs page not found")
        else:
            checks_passed.append("[C] Product Specs page found")

        page_id = page.get("_id")
        page_blocks = _get_blocks_for_page(final_state_backend, page_id)
        sorted_blocks = sorted(page_blocks, key=lambda b: b.get("order", 0))

        # Check for heading_2 '🔍 Requirements Traceability'
        trace_heading_found = False
        for block in sorted_blocks:
            if block.get("type") in ["heading2", "heading_2"]:
                content = block.get("content", "")
                if "🔍" in content and "requirements traceability" in content.lower():
                    trace_heading_found = True
                    break

        if not trace_heading_found:
            errors.append("[X] heading_2 '🔍 Requirements Traceability' not found")
        else:
            checks_passed.append("[C] Requirements Traceability heading found")

        # Check for gray callout with 📋 icon
        gray_callout_found = False
        for block in sorted_blocks:
            if block.get("type") == "callout":
                properties = block.get("properties", {})
                bg_color = properties.get("backgroundColor", block.get("backgroundColor", ""))
                icon = properties.get("icon", block.get("icon", ""))
                content = block.get("content", "").lower()
                if bg_color and "gray" in bg_color.lower():
                    if "📋" in (icon or "") or "user story" in content:
                        gray_callout_found = True
                        break

        if not gray_callout_found:
            errors.append("[X] Gray callout with user story mapping text not found")
        else:
            checks_passed.append("[C] Requirements callout found")

        # Check for Requirement heading_3 blocks
        requirement_headings = 0
        for block in sorted_blocks:
            if block.get("type") in ["heading3", "heading_3"]:
                content = block.get("content", "").lower()
                if "requirement" in content:
                    requirement_headings += 1

        if requirement_headings < 1:
            errors.append("[X] No Requirement [N] headings found")
        else:
            checks_passed.append(f"[C] {requirement_headings} requirement heading(s) found")

        # Check for unchecked todos (3 per requirement: spec, mockups, test cases)
        requirement_todos = 0
        required_todo_keywords = ["spec", "mockup", "test case"]
    
        for block in sorted_blocks:
            if block.get("type") in ["todo", "to_do"]:
                content = block.get("content", "").lower()
                if any(kw in content for kw in required_todo_keywords):
                    requirement_todos += 1

        if requirement_todos < 3:
            errors.append(f"[X] Expected at least 3 requirement todos, found {requirement_todos}")
        else:
            checks_passed.append(f"[C] {requirement_todos} requirement todos found")

        # Check for dividers
        divider_count = sum(1 for b in sorted_blocks if b.get("type") == "divider")
        if divider_count < 1:
            errors.append("[X] No dividers found after requirement groups")
        else:
            checks_passed.append("[C] Dividers found")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_project_guidelines_callout_reorganization(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate callout reorganization and Quick Reference section."""
    errors: list[str] = []

    checks_passed = []

    # Find Project Guidelines page
    try:
        page = _find_page_by_title(final_state_backend, "Project Guidelines")
        if not page:
            errors.append("[X] Project Guidelines & Best Practices page not found")
        else:
            checks_passed.append("[C] Project Guidelines & Best Practices page found")
    
        page_id = page.get("_id")
        page_blocks = _get_blocks_for_page(final_state_backend, page_id)
        sorted_blocks = sorted(page_blocks, key=lambda b: b.get("order", 0))

        # Find all callouts and their positions
        callouts = []
        for i, block in enumerate(sorted_blocks):
            if block.get("type") == "callout":
                properties = block.get("properties", {})
                bg_color = properties.get("backgroundColor", block.get("backgroundColor", ""))
                content = block.get("content", "").lower()
                callouts.append({
                    "index": i,
                    "color": bg_color.lower() if bg_color else "",
                    "content": content,
                    "icon": properties.get("icon", block.get("icon", ""))
                })

        # Check for blue callout with best practice text
        blue_callout = False
        for c in callouts:
            if "blue" in c["color"]:
                if "📘" in c["icon"] if c["icon"] else False:
                    if "feature branches" in c["content"] and "main branch" in c["content"]:
                        blue_callout = True
                        break

        if not blue_callout:
            errors.append("[X] Blue callout with 📘 icon about feature branches not found")
        else:
            checks_passed.append("[C] Blue best practice callout found")

        # Check for divider at end
        divider_found = False
        for block in sorted_blocks[-10:]:  # Check last few blocks
            if block.get("type") == "divider":
                divider_found = True
                break

        if not divider_found:
            errors.append("[X] Divider not found at end of page")
        else:
            checks_passed.append("[C] Divider found")

        # Check for Quick Reference heading at end
        quick_ref_found = False
        for block in sorted_blocks[-5:]:  # Check last few blocks
            if block.get("type") in ["heading2", "heading_2"]:
                content = block.get("content", "")
                if "quick reference" in content.lower():
                    quick_ref_found = True
                    break

        if not quick_ref_found:
            errors.append("[X] heading_2 'Quick Reference' not found at end")
        else:
            checks_passed.append("[C] Quick Reference heading found")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_project_health_dashboard(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Project Health Dashboard page under Project Documentation."""
    errors: list[str] = []

    checks_passed = []

    # Find Project Documentation page
    try:
        project_docs = _find_page_by_title(final_state_backend, "Project Documentation")
        if not project_docs:
            errors.append("[X] Project Documentation page not found")
        else:
            checks_passed.append("[C] Project Documentation page found")
    
        project_docs_id = project_docs.get("_id")
        checks_passed.append("[C] Project Documentation page found")

        # Find Project Health Dashboard as child
        dashboard = None
        child_pages = _get_child_pages(final_state_backend, project_docs_id)
        for child in child_pages:
            if "project health dashboard" in child.get("title", "").lower():
                dashboard = child
                break
    
        if not dashboard:
            errors.append("[X] Project Health Dashboard not found as child of Project Documentation")
        else:
            checks_passed.append("[C] Project Health Dashboard found as child of Project Documentation")
    
        page_id = dashboard.get("_id")
        page_blocks = _get_blocks_for_page(final_state_backend, page_id)
        sorted_blocks = sorted(page_blocks, key=lambda b: b.get("order", 0))
        checks_passed.append("[C] Project Health Dashboard page found")

        # Check 1: heading_1 '🏥 Project Health Dashboard'
        health_heading_found = False
        for block in sorted_blocks:
            if block.get("type") in ["heading1", "heading_1"]:
                content = block.get("content", "")
                if "🏥" in content and "project health dashboard" in content.lower():
                    health_heading_found = True
                    break

        if not health_heading_found:
            errors.append("[X] heading_1 '🏥 Project Health Dashboard' not found")
        else:
            checks_passed.append("[C] Health Dashboard heading_1 found")

        # Check 2: heading_2 '📊 Project Overview'
        overview_heading_found = False
        for block in sorted_blocks:
            if block.get("type") in ["heading2", "heading_2"]:
                content = block.get("content", "")
                if "📊" in content and "project overview" in content.lower():
                    overview_heading_found = True
                    break

        if not overview_heading_found:
            errors.append("[X] heading_2 '📊 Project Overview' not found")
        else:
            checks_passed.append("[C] Project Overview heading_2 found")

        # Check 3: heading_2 '🔍 Summary Statistics'
        summary_heading_found = False
        for block in sorted_blocks:
            if block.get("type") in ["heading2", "heading_2"]:
                content = block.get("content", "")
                if "🔍" in content and "summary statistics" in content.lower():
                    summary_heading_found = True
                    break

        if not summary_heading_found:
            errors.append("[X] heading_2 '🔍 Summary Statistics' not found")
        else:
            checks_passed.append("[C] Summary Statistics heading_2 found")

        # Check 4: Blue callout with 📈 icon
        blue_callout_found = False
        for block in sorted_blocks:
            if block.get("type") == "callout":
                properties = block.get("properties", {})
                bg_color = properties.get("backgroundColor", block.get("backgroundColor", ""))
                icon = properties.get("icon", block.get("icon", ""))
            
                has_blue_bg = "blue" in bg_color.lower() if bg_color else False
                has_chart_icon = "📈" in icon if icon else False
            
                if has_blue_bg and has_chart_icon:
                    blue_callout_found = True
                    break

        if not blue_callout_found:
            errors.append("[X] Blue callout with 📈 icon not found")
        else:
            checks_passed.append("[C] Blue callout with dashboard date found")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_project_health_report_comprehensive(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate comprehensive Project Health Report page creation."""
    errors: list[str] = []

    checks_passed = []

    # Find Project Documentation page
    try:
        project_doc = _find_page_by_title(final_state_backend, "Project Documentation")
        if not project_doc:
            errors.append("[X] Project Documentation page not found")
        else:
            checks_passed.append("[C] Project Documentation page found")

        # Find Project Health Report as child
        health_report = _find_page_by_title(final_state_backend, "Project Health Report")
        if not health_report:
            errors.append("[X] Project Health Report page not found")
        else:
            checks_passed.append("[C] Project Health Report page found")

        # Check parent relationship
        if health_report.get("parentId") != project_doc.get("_id"):
            errors.append("[X] Project Health Report is not under Project Documentation")
        else:
            checks_passed.append("[C] Project Health Report page found under Project Documentation")

        page_id = health_report.get("_id")
        page_blocks = _get_blocks_for_page(final_state_backend, page_id)
        sorted_blocks = sorted(page_blocks, key=lambda b: b.get("order", 0))

        # Check for heading_1 '📊 Project Health Report'
        main_heading_found = False
        for block in sorted_blocks:
            if block.get("type") in ["heading1", "heading_1"]:
                content = block.get("content", "")
                if "📊" in content and "project health report" in content.lower():
                    main_heading_found = True
                    break

        if not main_heading_found:
            errors.append("[X] heading_1 '📊 Project Health Report' not found")
        else:
            checks_passed.append("[C] Main heading found")

        # Check for heading_2 '🔍 Executive Summary'
        summary_heading_found = False
        for block in sorted_blocks:
            if block.get("type") in ["heading2", "heading_2"]:
                content = block.get("content", "")
                if "🔍" in content and "executive summary" in content.lower():
                    summary_heading_found = True
                    break

        if not summary_heading_found:
            errors.append("[X] heading_2 '🔍 Executive Summary' not found")
        else:
            checks_passed.append("[C] Executive Summary heading found")

        # Check for callout (either red or green based on completion)
        callout_found = False
        for block in sorted_blocks:
            if block.get("type") == "callout":
                properties = block.get("properties", {})
                bg_color = properties.get("backgroundColor", block.get("backgroundColor", ""))
                content = block.get("content", "").lower()
                if bg_color:
                    if ("red" in bg_color.lower() and "attention" in content) or \
                       ("green" in bg_color.lower() and "on track" in content):
                        callout_found = True
                        break

        if not callout_found:
            errors.append("[X] Conditional callout (red/green) not found")
        else:
            checks_passed.append("[C] Conditional callout found")

        # Check for project heading_3 blocks
        project_headings = 0
        for block in sorted_blocks:
            if block.get("type") in ["heading3", "heading_3"]:
                content = block.get("content", "")
                if "📁" in content:
                    project_headings += 1

        if project_headings < 1:
            errors.append("[X] No project headings (📁) found")
        else:
            checks_passed.append(f"[C] {project_headings} project heading(s) found")

        # Check for todo blocks (progress bar representation)
        todo_blocks = [b for b in sorted_blocks if b.get("type") in ["todo", "to_do"]]
        if len(todo_blocks) < 10:
            errors.append(f"[X] Expected at least 10 todo blocks for progress bar, found {len(todo_blocks)}")
        else:
            checks_passed.append("[C] Progress bar todo blocks found")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_project_status_dashboard(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Project Status Dashboard creation with aggregated data."""
    errors: list[str] = []

    checks_passed = []

    # Find Project Status Dashboard page
    try:
        dashboard = _find_page_by_title(final_state_backend, "Project Status Dashboard")
        if not dashboard:
            errors.append("[X] Project Status Dashboard page not found")
        else:
            checks_passed.append("[C] Project Status Dashboard page found")

        page_id = dashboard.get("_id")
        page_blocks = _get_blocks_for_page(final_state_backend, page_id)
        sorted_blocks = sorted(page_blocks, key=lambda b: b.get("order", 0))

        # Check for heading_1 '🎯 Project Status Dashboard'
        main_heading_found = False
        for block in sorted_blocks:
            if block.get("type") in ["heading1", "heading_1"]:
                content = block.get("content", "")
                if "🎯" in content and "project status dashboard" in content.lower():
                    main_heading_found = True
                    break

        if not main_heading_found:
            errors.append("[X] heading_1 '🎯 Project Status Dashboard' not found")
        else:
            checks_passed.append("[C] Main heading found")

        # Check for heading_2 '📅 Latest Sprint Summary'
        sprint_heading_found = False
        for block in sorted_blocks:
            if block.get("type") in ["heading2", "heading_2"]:
                content = block.get("content", "")
                if "📅" in content and "sprint summary" in content.lower():
                    sprint_heading_found = True
                    break

        if not sprint_heading_found:
            errors.append("[X] heading_2 '📅 Latest Sprint Summary' not found")
        else:
            checks_passed.append("[C] Sprint Summary heading found")

        # Check for heading_2 '🔄 Retrospective Insights'
        retro_heading_found = False
        for block in sorted_blocks:
            if block.get("type") in ["heading2", "heading_2"]:
                content = block.get("content", "")
                if "🔄" in content and "retrospective" in content.lower():
                    retro_heading_found = True
                    break

        if not retro_heading_found:
            errors.append("[X] heading_2 '🔄 Retrospective Insights' not found")
        else:
            checks_passed.append("[C] Retrospective Insights heading found")

        # Check for heading_2 '🐛 Bug Status Overview'
        bug_heading_found = False
        for block in sorted_blocks:
            if block.get("type") in ["heading2", "heading_2"]:
                content = block.get("content", "")
                if "🐛" in content and "bug" in content.lower():
                    bug_heading_found = True
                    break

        if not bug_heading_found:
            errors.append("[X] heading_2 '🐛 Bug Status Overview' not found")
        else:
            checks_passed.append("[C] Bug Status Overview heading found")

        # Check for red callout with Critical bugs info
        critical_callout_found = False
        for block in sorted_blocks:
            if block.get("type") == "callout":
                properties = block.get("properties", {})
                bg_color = properties.get("backgroundColor", block.get("backgroundColor", ""))
                content = block.get("content", "").lower()
                if bg_color and "red" in bg_color.lower():
                    if "critical" in content:
                        critical_callout_found = True
                        break

        if not critical_callout_found:
            errors.append("[X] Red callout with Critical bug info not found")
        else:
            checks_passed.append("[C] Critical bugs callout found")

        # Check for heading_2 '📈 Overall Health Score'
        health_heading_found = False
        for block in sorted_blocks:
            if block.get("type") in ["heading2", "heading_2"]:
                content = block.get("content", "")
                if "📈" in content and "health score" in content.lower():
                    health_heading_found = True
                    break

        if not health_heading_found:
            errors.append("[X] heading_2 '📈 Overall Health Score' not found")
        else:
            checks_passed.append("[C] Overall Health Score heading found")

        # Check for paragraph with completion percentages
        health_paragraph_found = False
        for block in sorted_blocks:
            if block.get("type") == "paragraph":
                content = block.get("content", "").lower()
                if "sprint completion" in content and "bug resolution" in content:
                    health_paragraph_found = True
                    break

        if not health_paragraph_found:
            errors.append("[X] Health score paragraph with percentages not found")
        else:
            checks_passed.append("[C] Health score paragraph found")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_sprint_planning_analysis_section(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Sprint Planning Analysis section with metrics."""
    errors: list[str] = []

    checks_passed = []

    # Find Sprint Planning page
    try:
        page = _find_page_by_title(final_state_backend, "Sprint Planning")
        if not page:
            errors.append("[X] Sprint Planning - Jan 15 page not found")
        else:
            checks_passed.append("[C] Sprint Planning - Jan 15 page found")

        page_id = page.get("_id")
        page_blocks = _get_blocks_for_page(final_state_backend, page_id)
        sorted_blocks = sorted(page_blocks, key=lambda b: b.get("order", 0))

        # Check for heading_1 '📊 Sprint Analysis'
        analysis_heading_found = False
        for block in sorted_blocks:
            if block.get("type") in ["heading1", "heading_1"]:
                content = block.get("content", "")
                if "📊" in content and "sprint analysis" in content.lower():
                    analysis_heading_found = True
                    break

        if not analysis_heading_found:
            errors.append("[X] heading_1 '📊 Sprint Analysis' not found")
        else:
            checks_passed.append("[C] Sprint Analysis heading found")

        # Check for heading_2 '✅ Task Completion Metrics'
        metrics_heading_found = False
        for block in sorted_blocks:
            if block.get("type") in ["heading2", "heading_2"]:
                content = block.get("content", "")
                if "✅" in content and "task completion metrics" in content.lower():
                    metrics_heading_found = True
                    break

        if not metrics_heading_found:
            errors.append("[X] heading_2 '✅ Task Completion Metrics' not found")
        else:
            checks_passed.append("[C] Task Completion Metrics heading found")

        # Check for green callout with completion rate
        green_callout_found = False
        for block in sorted_blocks:
            if block.get("type") == "callout":
                properties = block.get("properties", {})
                bg_color = properties.get("backgroundColor", block.get("backgroundColor", ""))
                content = block.get("content", "").lower()
                if bg_color and "green" in bg_color.lower():
                    if "sprint completion rate" in content:
                        green_callout_found = True
                        break

        if not green_callout_found:
            errors.append("[X] Green callout with completion rate not found")
        else:
            checks_passed.append("[C] Completion rate callout found")

        # Check for heading_2 '📋 Task Breakdown'
        breakdown_heading_found = False
        for block in sorted_blocks:
            if block.get("type") in ["heading2", "heading_2"]:
                content = block.get("content", "")
                if "📋" in content and "task breakdown" in content.lower():
                    breakdown_heading_found = True
                    break

        if not breakdown_heading_found:
            errors.append("[X] heading_2 '📋 Task Breakdown' not found")
        else:
            checks_passed.append("[C] Task Breakdown heading found")

        # Check for numbered list with task counts
        numbered_items = 0
        for block in sorted_blocks:
            if block.get("type") in ["numberedList", "numbered_list", "numberedListItem", "numbered_list_item"]:
                content = block.get("content", "").lower()
                if any(x in content for x in ["total tasks", "completed tasks", "remaining tasks", "average completion"]):
                    numbered_items += 1

        if numbered_items < 4:
            errors.append(f"[X] Expected 4 numbered list items for task breakdown, found {numbered_items}")
        else:
            checks_passed.append("[C] Task breakdown numbered list found")

        # Check for quote block with motivational text
        quote_found = False
        for block in sorted_blocks:
            if block.get("type") == "quote":
                content = block.get("content", "").lower()
                if "success is the sum" in content and "small efforts" in content:
                    quote_found = True
                    break

        if not quote_found:
            errors.append("[X] Quote block with motivational text not found")
        else:
            checks_passed.append("[C] Motivational quote found")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_sprint_planning_progress_metrics(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Sprint Progress Metrics section with KPIs."""
    errors: list[str] = []

    checks_passed = []

    # Find Sprint Planning page
    try:
        page = _find_page_by_title(final_state_backend, "Sprint Planning")
        if not page:
            errors.append("[X] Sprint Planning - Jan 15 page not found")
        else:
            checks_passed.append("[C] Sprint Planning - Jan 15 page found")
    
        page_id = page.get("_id")
        page_blocks = _get_blocks_for_page(final_state_backend, page_id)
        sorted_blocks = sorted(page_blocks, key=lambda b: b.get("order", 0))

        # Check for Sprint Progress Metrics heading
        metrics_heading = False
        for block in sorted_blocks:
            if block.get("type") in ["heading2", "heading_2"]:
                content = block.get("content", "")
                if "📊" in content and "sprint progress metrics" in content.lower():
                    metrics_heading = True
                    break

        if not metrics_heading:
            errors.append("[X] heading_2 '📊 Sprint Progress Metrics' not found")
        else:
            checks_passed.append("[C] Sprint Progress Metrics heading found")

        # Check for blue callout with KPI
        kpi_callout = False
        for block in sorted_blocks:
            if block.get("type") == "callout":
                properties = block.get("properties", {})
                bg_color = properties.get("backgroundColor", block.get("backgroundColor", ""))
                icon = properties.get("icon", block.get("icon", ""))
                content = block.get("content", "").lower()
                if "blue" in bg_color.lower() if bg_color else False:
                    if "📈" in icon if icon else False:
                        if "key performance indicators" in content:
                            kpi_callout = True
                            break

        if not kpi_callout:
            errors.append("[X] Blue callout with KPI text not found")
        else:
            checks_passed.append("[C] KPI callout found")

        # Check for numbered list with 3 items
        numbered_items = 0
        for block in sorted_blocks:
            if block.get("type") in ["numberedList", "numbered_list", "numberedListItem", "numbered_list_item"]:
                content = block.get("content", "").lower()
                if any(x in content for x in ["story points", "completed tasks", "velocity trend"]):
                    numbered_items += 1

        if numbered_items < 3:
            errors.append(f"[X] Expected 3 numbered list items, found {numbered_items}")
        else:
            checks_passed.append("[C] 3 numbered list items found")

        # Check for divider
        divider_found = any(b.get("type") == "divider" for b in sorted_blocks)
        if not divider_found:
            errors.append("[X] Divider not found")
        else:
            checks_passed.append("[C] Divider found")

        # Check for paragraph with timestamp (italic formatting)
        timestamp_found = False
        for block in sorted_blocks:
            if block.get("type") == "paragraph":
                content = block.get("content", "").lower()
                if "last updated" in content:
                    timestamp_found = True
                    break

        if not timestamp_found:
            errors.append("[X] Timestamp paragraph not found")
        else:
            checks_passed.append("[C] Timestamp paragraph found")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_sprint_planning_updates_section(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Sprint Planning updates section with completion callout."""
    errors: list[str] = []

    checks_passed = []

    # Find Sprint Planning page
    try:
        page = _find_page_by_title(final_state_backend, "Sprint Planning")
        if not page:
            errors.append("[X] Sprint Planning - Jan 15 page not found")
        else:
            checks_passed.append("[C] Sprint Planning - Jan 15 page found")

        page_id = page.get("_id")
        page_blocks = _get_blocks_for_page(final_state_backend, page_id)
        sorted_blocks = sorted(page_blocks, key=lambda b: b.get("order", 0))

        # Check for dividers (should have 2 new ones)
        divider_count = sum(1 for b in sorted_blocks if b.get("type") == "divider")
        if divider_count < 2:
            errors.append(f"[X] Expected at least 2 dividers, found {divider_count}")
        else:
            checks_passed.append("[C] Dividers found")

        # Check for bold paragraph with date
        date_paragraph_found = False
        for block in sorted_blocks:
            if block.get("type") == "paragraph":
                content = block.get("content", "")
                if "updates" in content.lower() and ("december" in content.lower() or "2024" in content):
                    date_paragraph_found = True
                    break

        if not date_paragraph_found:
            errors.append("[X] Updates paragraph with date not found")
        else:
            checks_passed.append("[C] Updates date paragraph found")

        # Check for checked todos with ✅ emoji
        checked_with_emoji = 0
        for block in sorted_blocks:
            if block.get("type") in ["todo", "to_do"]:
                properties = block.get("properties", {})
                checked = properties.get("checked", block.get("checked", False))
                content = block.get("content", "")
                if checked and "✅" in content:
                    checked_with_emoji += 1

        if checked_with_emoji < 2:
            errors.append(f"[X] Expected 2 checked todos with ✅, found {checked_with_emoji}")
        else:
            checks_passed.append("[C] 2 checked todos with ✅ found")

        # Check for unchecked todo about follow-up meeting
        followup_todo_found = False
        for block in sorted_blocks:
            if block.get("type") in ["todo", "to_do"]:
                properties = block.get("properties", {})
                checked = properties.get("checked", block.get("checked", False))
                content = block.get("content", "").lower()
                if not checked and "follow-up" in content and "meeting" in content:
                    followup_todo_found = True
                    break

        if not followup_todo_found:
            errors.append("[X] Unchecked follow-up meeting todo not found")
        else:
            checks_passed.append("[C] Follow-up meeting todo found")

        # Check for green callout with 🎉 and completion message
        green_callout_found = False
        for block in sorted_blocks:
            if block.get("type") == "callout":
                properties = block.get("properties", {})
                bg_color = properties.get("backgroundColor", block.get("backgroundColor", ""))
                icon = properties.get("icon", block.get("icon", ""))
                content = block.get("content", "").lower()
                if bg_color and "green" in bg_color.lower():
                    if "🎉" in (icon or "") or "🎉" in block.get("content", ""):
                        if "sprint goal" in content and "achieved" in content:
                            green_callout_found = True
                            break

        if not green_callout_found:
            errors.append("[X] Green callout with 🎉 and completion message not found")
        else:
            checks_passed.append("[C] Sprint goal achievement callout found")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_sprint_planning_velocity_section(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate sprint velocity tracking section with code blocks."""
    errors: list[str] = []

    checks_passed = []

    # Find Sprint Planning page
    try:
        page = _find_page_by_title(final_state_backend, "Sprint Planning")
        if not page:
            errors.append("[X] Sprint Planning - Jan 15 page not found")
        else:
            checks_passed.append("[C] Sprint Planning - Jan 15 page found")
    
        page_id = page.get("_id")
        page_blocks = _get_blocks_for_page(final_state_backend, page_id)
        sorted_blocks = sorted(page_blocks, key=lambda b: b.get("order", 0))

        # Check for Sprint Velocity Tracking heading
        velocity_heading = False
        for block in sorted_blocks:
            if block.get("type") in ["heading2", "heading_2"]:
                content = block.get("content", "")
                if "📈" in content and "sprint velocity tracking" in content.lower():
                    velocity_heading = True
                    break

        if not velocity_heading:
            errors.append("[X] heading_2 '📈 Sprint Velocity Tracking' not found")
        else:
            checks_passed.append("[C] Velocity Tracking heading found")

        # Check for quote block
        quote_found = False
        for block in sorted_blocks:
            if block.get("type") == "quote":
                content = block.get("content", "").lower()
                if "velocity" in content and "agile alliance" in content:
                    quote_found = True
                    break

        if not quote_found:
            errors.append("[X] Quote block with Agile Alliance reference not found")
        else:
            checks_passed.append("[C] Agile Alliance quote found")

        # Check for JSON code block
        json_code = False
        for block in sorted_blocks:
            if block.get("type") == "code":
                properties = block.get("properties", {})
                language = properties.get("language", block.get("language", ""))
                content = block.get("content", "")
                if language.lower() == "json":
                    if "sprint_1" in content and "21" in content:
                        json_code = True
                        break

        if not json_code:
            errors.append("[X] JSON code block with sprint data not found")
        else:
            checks_passed.append("[C] JSON code block found")

        # Check for JavaScript code block
        js_code = False
        for block in sorted_blocks:
            if block.get("type") == "code":
                properties = block.get("properties", {})
                language = properties.get("language", block.get("language", ""))
                content = block.get("content", "")
                if language.lower() == "javascript":
                    if "avgVelocity" in content or "reduce" in content:
                        js_code = True
                        break

        if not js_code:
            errors.append("[X] JavaScript code block with velocity calculation not found")
        else:
            checks_passed.append("[C] JavaScript code block found")

        # Check for markdown code block
        md_code = False
        for block in sorted_blocks:
            if block.get("type") == "code":
                properties = block.get("properties", {})
                language = properties.get("language", block.get("language", ""))
                content = block.get("content", "")
                if language.lower() == "markdown":
                    if "Sprint" in content and "Points" in content:
                        md_code = True
                        break

        if not md_code:
            errors.append("[X] Markdown code block with table not found")
        else:
            checks_passed.append("[C] Markdown table code block found")

        # Check for green callout
        green_callout = False
        for block in sorted_blocks:
            if block.get("type") == "callout":
                properties = block.get("properties", {})
                bg_color = properties.get("backgroundColor", block.get("backgroundColor", ""))
                content = block.get("content", "").lower()
                if "green" in bg_color.lower() if bg_color else False:
                    if "20-22" in content and "story points" in content:
                        green_callout = True
                        break

        if not green_callout:
            errors.append("[X] Green callout about 20-22 story points target not found")
        else:
            checks_passed.append("[C] Green velocity target callout found")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_team_workload_analysis(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Team Workload Analysis page with task distribution and top performer."""
    errors: list[str] = []

    checks_passed = []

    # Find Team Directory page
    try:
        team_directory = _find_page_by_title(final_state_backend, "Team Directory")
        if not team_directory:
            errors.append("[X] Team Directory page not found")
        else:
            checks_passed.append("[C] Team Directory page found")

        # Find Team Workload Analysis as sibling
        parent_id = team_directory.get("parentId")
        workload_analysis = _find_child_by_title_with_id(final_state_backend, parent_id, "Team Workload Analysis")
    
        if not workload_analysis:
            errors.append("[X] Team Workload Analysis page not found as sibling to Team Directory")
        else:
            checks_passed.append("[C] Team Workload Analysis page found")

        page_id = workload_analysis.get("_id")
        page_blocks = _get_blocks_for_page(final_state_backend, page_id)
        sorted_blocks = sorted(page_blocks, key=lambda b: b.get("order", 0))

        # Check for heading_1 '👥 Team Workload Analysis'
        main_heading = None
        for block in sorted_blocks:
            if block.get("type") in ["heading1", "heading_1"]:
                content = block.get("content", "")
                if "👥" in content and "team workload analysis" in content.lower():
                    main_heading = block
                    break

        if not main_heading:
            errors.append("[X] heading_1 '👥 Team Workload Analysis' not found")
        else:
            checks_passed.append("[C] Main heading found")

        # Check for Team Performance Summary with gold callout
        summary_idx = None
        for i, block in enumerate(sorted_blocks):
            if block.get("type") in ["heading2", "heading_2"]:
                content = block.get("content", "")
                if "🏆" in content and "team performance summary" in content.lower():
                    summary_idx = i
                    break

        if summary_idx is None:
            errors.append("[X] heading_2 '🏆 Team Performance Summary' not found")
        else:
            checks_passed.append("[C] Team Performance Summary heading found")

        # Check for gold callout with top performer
        gold_callout = False
        for i in range(summary_idx + 1, min(summary_idx + 5, len(sorted_blocks))):
            block = sorted_blocks[i]
            if block.get("type") == "callout":
                properties = block.get("properties", {})
                bg_color = properties.get("backgroundColor", block.get("backgroundColor", ""))
                content = block.get("content", "")
            
                if "gold" in bg_color.lower() if bg_color else False:
                    if "top performer:" in content.lower():
                        gold_callout = True
                        break

        if not gold_callout:
            errors.append("[X] Gold callout with top performer not found")
        else:
            checks_passed.append("[C] Gold callout with top performer found")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_weekly_standup_current_blockers(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Weekly Standup Current Blockers section addition."""
    errors: list[str] = []

    checks_passed = []

    # Find Weekly Standup Template page
    try:
        page = _find_page_by_title(final_state_backend, "Weekly Standup Template")
        if not page:
            errors.append("[X] Weekly Standup Template page not found")
        else:
            checks_passed.append("[C] Weekly Standup Template page found")

        page_id = page.get("_id")
        page_blocks = _get_blocks_for_page(final_state_backend, page_id)
        sorted_blocks = sorted(page_blocks, key=lambda b: b.get("order", 0))

        # Check for heading_2 '🚧 Current Blockers'
        blockers_heading_found = False
        for block in sorted_blocks:
            if block.get("type") in ["heading2", "heading_2"]:
                content = block.get("content", "")
                if "🚧" in content and "current blockers" in content.lower():
                    blockers_heading_found = True
                    break

        if not blockers_heading_found:
            errors.append("[X] heading_2 '🚧 Current Blockers' not found")
        else:
            checks_passed.append("[C] Current Blockers heading found")

        # Check for three unchecked todos with specific content
        required_todos = [
            ("⚠️", "design review", "authentication"),
            ("🔴", "backend api", "rate limiting"),
            ("📊", "q2 metrics", "dashboard"),
        ]
        todos_found = 0
    
        for block in sorted_blocks:
            if block.get("type") in ["todo", "to_do"]:
                properties = block.get("properties", {})
                checked = properties.get("checked", block.get("checked", False))
                content = block.get("content", "").lower()
            
                for emoji, keyword1, keyword2 in required_todos:
                    if emoji in block.get("content", "") and keyword1 in content and keyword2 in content:
                        if not checked:
                            todos_found += 1
                            break

        if todos_found < 3:
            errors.append(f"[X] Expected 3 unchecked blocker todos, found {todos_found}")
        else:
            checks_passed.append("[C] 3 blocker todos found")

        # Check for divider
        divider_found = any(b.get("type") == "divider" for b in sorted_blocks)
        if not divider_found:
            errors.append("[X] Divider not found")
        else:
            checks_passed.append("[C] Divider found")

        # Check for yellow callout at end with reminder text
        yellow_callout_found = False
        for block in sorted_blocks:
            if block.get("type") == "callout":
                properties = block.get("properties", {})
                bg_color = properties.get("backgroundColor", block.get("backgroundColor", ""))
                content = block.get("content", "").lower()
                if bg_color and "yellow" in bg_color.lower():
                    if "💡" in block.get("content", "") or "remember" in content:
                        if "friday" in content and "standup" in content:
                            yellow_callout_found = True
                            break

        if not yellow_callout_found:
            errors.append("[X] Yellow callout with Friday reminder not found")
        else:
            checks_passed.append("[C] Yellow reminder callout found")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_weekly_standup_focus_areas_analytics(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Weekly Standup Focus Areas section with analytics."""
    errors: list[str] = []

    checks_passed = []

    # Find Weekly Standup Template page
    try:
        page = _find_page_by_title(final_state_backend, "Weekly Standup Template")
        if not page:
            errors.append("[X] Weekly Standup Template page not found")
        else:
            checks_passed.append("[C] Weekly Standup Template page found")

        page_id = page.get("_id")
        page_blocks = _get_blocks_for_page(final_state_backend, page_id)
        sorted_blocks = sorted(page_blocks, key=lambda b: b.get("order", 0))

        # Check for heading_2 '🎯 Focus Areas'
        focus_heading_found = False
        focus_heading_order = -1
        for block in sorted_blocks:
            if block.get("type") in ["heading2", "heading_2"]:
                content = block.get("content", "")
                if "🎯" in content and "focus areas" in content.lower():
                    focus_heading_found = True
                    focus_heading_order = block.get("order", 0)
                    break

        if not focus_heading_found:
            errors.append("[X] heading_2 '🎯 Focus Areas' not found")
        else:
            checks_passed.append("[C] Focus Areas heading found")

        # Check for yellow callout with ⚡ icon
        yellow_callout_found = False
        for block in sorted_blocks:
            if block.get("type") == "callout":
                properties = block.get("properties", {})
                bg_color = properties.get("backgroundColor", block.get("backgroundColor", ""))
                icon = properties.get("icon", block.get("icon", ""))
                content = block.get("content", "").lower()
                if bg_color and "yellow" in bg_color.lower():
                    if "⚡" in (icon or ""):
                        if "prioritize" in content and "okr" in content:
                            yellow_callout_found = True
                            break

        if not yellow_callout_found:
            errors.append("[X] Yellow callout with ⚡ icon and OKR text not found")
        else:
            checks_passed.append("[C] Yellow callout with OKR text found")

        # Check for summary paragraph with task counts
        summary_found = False
        for block in sorted_blocks:
            if block.get("type") == "paragraph":
                content = block.get("content", "").lower()
                if "this week's progress" in content and "tasks completed" in content:
                    summary_found = True
                    break

        if not summary_found:
            errors.append("[X] Summary paragraph with task counts not found")
        else:
            checks_passed.append("[C] Summary paragraph found")

        # Check for divider
        divider_found = any(b.get("type") == "divider" for b in sorted_blocks)
        if not divider_found:
            errors.append("[X] Divider not found")
        else:
            checks_passed.append("[C] Divider found")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_weekly_standup_sprint_goals_section(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate weekly standup sprint goals section with metrics and todos."""
    errors: list[str] = []

    checks_passed = []

    # Find Weekly Standup Template page
    try:
        page = _find_page_by_title(final_state_backend, "Weekly Standup Template")
        if not page:
            errors.append("[X] Weekly Standup Template page not found")
        else:
            checks_passed.append("[C] Weekly Standup Template page found")
    
        page_id = page.get("_id")
        page_blocks = _get_blocks_for_page(final_state_backend, page_id)
        sorted_blocks = sorted(page_blocks, key=lambda b: b.get("order", 0))

        # Check for divider after Blockers heading
        blockers_idx = None
        for i, block in enumerate(sorted_blocks):
            if block.get("type") in ["heading2", "heading_2", "heading3", "heading_3"]:
                content = block.get("content", "")
                if "blocker" in content.lower():
                    blockers_idx = i
                    break

        if blockers_idx is None:
            errors.append("[X] Blockers heading not found")
        else:
            checks_passed.append("[C] Blockers heading found")

        # Find divider after blockers
        divider_found = False
        for i in range(blockers_idx + 1, len(sorted_blocks)):
            if sorted_blocks[i].get("type") == "divider":
                divider_found = True
                break

        if not divider_found:
            errors.append("[X] Divider after Blockers not found")
        else:
            checks_passed.append("[C] Divider found after Blockers")

        # Check for Week of January 29, 2024 heading
        week_heading_found = False
        for block in sorted_blocks:
            if block.get("type") in ["heading2", "heading_2"]:
                content = block.get("content", "")
                if "📅" in content and "week of january 29" in content.lower():
                    week_heading_found = True
                    break

        if not week_heading_found:
            errors.append("[X] heading_2 '📅 Week of January 29, 2024' not found")
        else:
            checks_passed.append("[C] Week of January 29, 2024 heading found")

        # Check for Sprint Goals heading
        sprint_goals_found = False
        for block in sorted_blocks:
            if block.get("type") in ["heading3", "heading_3"]:
                content = block.get("content", "")
                if "🎯" in content and "sprint goals" in content.lower():
                    sprint_goals_found = True
                    break

        if not sprint_goals_found:
            errors.append("[X] heading_3 '🎯 Sprint Goals' not found")
        else:
            checks_passed.append("[C] Sprint Goals heading found")

        # Check for 3 unchecked todos with specific content
        required_todos = [
            "complete api integration",
            "implement analytics dashboard",
            "conduct code review"
        ]
        found_todos = 0
        for block in sorted_blocks:
            if block.get("type") in ["todo", "to_do", "checkbox"]:
                content = block.get("content", "").lower()
                for req in required_todos:
                    if req in content:
                        found_todos += 1
                        break

        if found_todos < 3:
            errors.append(f"[X] Expected 3 specific todos, found {found_todos}")
        else:
            checks_passed.append("[C] 3 sprint goal todos found")

        # Check for Metrics heading
        metrics_found = False
        for block in sorted_blocks:
            if block.get("type") in ["heading3", "heading_3"]:
                content = block.get("content", "")
                if "📈" in content and "metrics" in content.lower():
                    metrics_found = True
                    break

        if not metrics_found:
            errors.append("[X] heading_3 '📈 Metrics' not found")
        else:
            checks_passed.append("[C] Metrics heading found")

        # Check for blue callout with velocity
        velocity_callout_found = False
        for block in sorted_blocks:
            if block.get("type") == "callout":
                properties = block.get("properties", {})
                bg_color = properties.get("backgroundColor", block.get("backgroundColor", ""))
                content = block.get("content", "").lower()
                if "blue" in bg_color.lower() if bg_color else False:
                    if "velocity" in content:
                        velocity_callout_found = True
                        break

        if not velocity_callout_found:
            errors.append("[X] Blue callout with velocity metrics not found")
        else:
            checks_passed.append("[C] Blue velocity callout found")

        # Check for italic note paragraph
        italic_note_found = False
        for block in sorted_blocks:
            if block.get("type") == "paragraph":
                content = block.get("content", "")
                if "update velocity" in content.lower() and "sprint" in content.lower():
                    italic_note_found = True
                    break

        if not italic_note_found:
            errors.append("[X] Italic note about velocity not found")
        else:
            checks_passed.append("[C] Velocity note paragraph found")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_weekly_standup_weekly_archive(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate weekly archive section with todo analysis."""
    errors: list[str] = []

    checks_passed = []

    # Find Weekly Standup Template page
    try:
        page = _find_page_by_title(final_state_backend, "Weekly Standup Template")
        if not page:
            errors.append("[X] Weekly Standup Template page not found")
        else:
            checks_passed.append("[C] Weekly Standup Template page found")
    
        page_id = page.get("_id")
        page_blocks = _get_blocks_for_page(final_state_backend, page_id)
        sorted_blocks = sorted(page_blocks, key=lambda b: b.get("order", 0))

        # Check for divider
        divider_found = any(b.get("type") == "divider" for b in sorted_blocks)
        if not divider_found:
            errors.append("[X] Divider not found")
        else:
            checks_passed.append("[C] Divider found")

        # Check for Weekly Archive heading
        archive_heading = False
        for block in sorted_blocks:
            if block.get("type") in ["heading2", "heading_2"]:
                content = block.get("content", "")
                if "📅" in content and "weekly archive" in content.lower():
                    archive_heading = True
                    break

        if not archive_heading:
            errors.append("[X] heading_2 '📅 Weekly Archive' not found")
        else:
            checks_passed.append("[C] Weekly Archive heading found")

        # Check for Week of January 29, 2024 heading3
        week_heading = False
        for block in sorted_blocks:
            if block.get("type") in ["heading3", "heading_3"]:
                content = block.get("content", "")
                if "week of january 29" in content.lower():
                    week_heading = True
                    break

        if not week_heading:
            errors.append("[X] heading_3 'Week of January 29, 2024' not found")
        else:
            checks_passed.append("[C] Week date heading found")

        # Check for 3 specific unchecked todos
        required_todos = [
            "migrate legacy authentication",
            "implement analytics dashboard",
            "update design system"
        ]
        found_todos = 0
        for block in sorted_blocks:
            if block.get("type") in ["todo", "to_do", "checkbox"]:
                content = block.get("content", "").lower()
                for req in required_todos:
                    if req in content:
                        found_todos += 1
                        break

        if found_todos < 3:
            errors.append(f"[X] Expected 3 archive todos, found {found_todos}")
        else:
            checks_passed.append("[C] 3 archive todos found")

        # Check for orange callout with statistics
        stats_callout = False
        for block in sorted_blocks:
            if block.get("type") == "callout":
                properties = block.get("properties", {})
                bg_color = properties.get("backgroundColor", block.get("backgroundColor", ""))
                icon = properties.get("icon", block.get("icon", ""))
                content = block.get("content", "").lower()
                if "orange" in bg_color.lower() if bg_color else False:
                    if "📈" in icon if icon else False:
                        if "template contains" in content and "tasks" in content:
                            stats_callout = True
                            break

        if not stats_callout:
            errors.append("[X] Orange callout with todo statistics not found")
        else:
            checks_passed.append("[C] Todo statistics callout found")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

    # -----------------------------------------------------------------------------
    # reorganize-engineering-documentation-v2
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_organise_project_planning_hub(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Task: Organize project planning into a structured hub with subsections.
    
    Validates:
    1. "Project Planning Hub" page exists with target icon
    2. Hub is marked as favorite
    3. Three subsection pages exist: Current Projects, Planning Templates, Completed Projects
    4. Existing "Project Plan" pages are parented under Current Projects
    5. "Project Plan Template" exists under Planning Templates with proper structure
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    # 1. Find "Project Planning Hub" page
    try:
        hub_pages = backend.query({
            "collection": "pages", 
            "filter": {"title": "Project Planning Hub"}
        })
    
        if not hub_pages:
            errors.append("[X] Page 'Project Planning Hub' not found")
        else:
            checks_passed.append("[C] Page 'Project Planning Hub' found")
    
        # Handle both single dict and list responses
        hub_page = hub_pages[0] if isinstance(hub_pages, list) else hub_pages
        hub_page_id = hub_page.get("_id")
    
        if not hub_page_id:
            errors.append("[X] Project Planning Hub page has no _id")
        else:
            checks_passed.append("[C] Project Planning Hub page has _id")
    
        # Check for target icon (🎯 dart/bullseye emoji)
        icon = hub_page.get("icon")
        if not icon or icon not in ["🎯", "\ud83c\udfaf"]:
            errors.append("[X] Project Planning Hub does not have a target icon")
        else:
            checks_passed.append("[C] Project Planning Hub has a target icon")
    
        # 2. Check if hub is marked as favorite
        if not hub_page.get("isFavorite"):
            errors.append("[X] Project Planning Hub is not marked as favorite")
        else:
            checks_passed.append("[C] Project Planning Hub is marked as favorite")
    
        # 3. Find and validate three subsection pages
        required_subsections = ["Current Projects", "Planning Templates", "Completed Projects"]
        subsection_ids = {}
    
        for subsection_name in required_subsections:
            subsection_pages = backend.query({
                "collection": "pages",
                "filter": {"title": subsection_name, "parentId": hub_page_id}
            })
        
            if not subsection_pages:
                errors.append(f"[X] Subsection '{subsection_name}' not found under Project Planning Hub")
            else:
                checks_passed.append(f"[C] Subsection '{subsection_name}' found under Project Planning Hub")
        
            subsection = subsection_pages[0] if isinstance(subsection_pages, list) else subsection_pages
            subsection_ids[subsection_name] = subsection.get("_id")
    
        # 4. Validate existing "Project Plan" pages are under Current Projects
        # Get all pages to find those containing "Project Plan" in title
        all_pages = backend.query({
            "collection": "pages",
            "filter": {}
        })
    
        if all_pages:
            if not isinstance(all_pages, list):
                all_pages = [all_pages]
        
            # Filter for pages with "Project Plan" in title, excluding the hub, template, and subsections
            excluded_titles = ["Project Planning Hub", "Project Plan Template"] + required_subsections
            actual_project_plans = [
                p for p in all_pages 
                if "Project Plan" in p.get("title", "") and p.get("title") not in excluded_titles
            ]
        
            # If there are existing project plan pages, they must be under Current Projects
            for plan_page in actual_project_plans:
                if plan_page.get("parentId") != subsection_ids["Current Projects"]:
                    errors.append(f"[X] Project Plan page '{plan_page.get('title')}' is not under Current Projects")
                else:
                    checks_passed.append(f"[C] Project Plan page '{plan_page.get('title')}' is under Current Projects")
    
        # 5. Validate "Project Plan Template" exists under Planning Templates
        template_pages = backend.query({
            "collection": "pages",
            "filter": {"title": "Project Plan Template", "parentId": subsection_ids["Planning Templates"]}
        })
    
        if not template_pages:
            errors.append("[X] Project Plan Template not found under Planning Templates")
        else:
            checks_passed.append("[C] Project Plan Template found under Planning Templates")
    
        template_page = template_pages[0] if isinstance(template_pages, list) else template_pages
        template_page_id = template_page.get("_id")

        # Check template has blocks/content
        blocks = _get_blocks_for_page(backend, template_page_id)
        if not blocks:
            errors.append("[X] Project Plan Template has no content blocks")
        else:
            checks_passed.append("[C] Project Plan Template has content blocks")
    
        # Validate template has required sections (objectives, timeline, resources, risks)
        required_sections = ["objective", "timeline", "resource", "risk"]
        template_text = " ".join([str(block.get("content", "")).lower() for block in blocks])
    
        missing_sections = []
        for section in required_sections:
            if section not in template_text:
                missing_sections.append(section)
    
        if missing_sections:
            errors.append(f"[X] Project Plan Template is missing sections: {', '.join(missing_sections)}")
        else:
            checks_passed.append("[C] Project Plan Template has all required sections")

        # Check for callouts and todos in template
        has_callout = any(block.get("type") == "callout" for block in blocks)
        has_todo = any(block.get("type") == "todo" for block in blocks)

        if not has_callout:
            errors.append("[X] Project Plan Template missing callouts for important notes")
        else:
            checks_passed.append("[C] Project Plan Template has callouts for important notes")

        if not has_todo:
            errors.append("[X] Project Plan Template missing todo checklists for milestones")
        else:
            checks_passed.append("[C] Project Plan Template has todo checklists for milestones")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

    # -----------------------------------------------------------------------------
    # create-documentation-structure-v2
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_create_documentation_structure(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Task: Create comprehensive documentation structure under Engineering Wiki.
    
    Validates:
    1. "Engineering Wiki" page exists
    2. Three new subpages created: API Reference, Code Examples, Troubleshooting Guide
    3. Each subpage has structured content (heading1, paragraph, divider, additional headings)
    4. Parent wiki has table of contents with bulleted links
    5. Total 4 child pages under Engineering Wiki
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    # 1. Find "Engineering Wiki" page
    try:
        wiki_pages = backend.query({
            "collection": "pages",
            "filter": {"title": "Engineering Wiki"}
        })
    
        if not wiki_pages:
            errors.append("[X] Engineering Wiki page not found")
        else:
            checks_passed.append("[C] Engineering Wiki page found")
    
        wiki_page = wiki_pages[0] if isinstance(wiki_pages, list) else wiki_pages
        wiki_page_id = wiki_page.get("_id")
    
        if not wiki_page_id:
            errors.append("[X] Engineering Wiki page has no _id")
        else:
            checks_passed.append("[C] Engineering Wiki page has _id")
    
        # 2. Find all child pages under Engineering Wiki
        child_pages = backend.query({
            "collection": "pages",
            "filter": {"parentId": wiki_page_id}
        })
    
        if not isinstance(child_pages, list):
            child_pages = [child_pages] if child_pages else []
    
        # 3. Check for required subpages
        required_subpages = ["API Reference", "Code Examples", "Troubleshooting Guide"]
        found_subpages = {}
    
        for subpage_name in required_subpages:
            matching_pages = [p for p in child_pages if p.get("title") == subpage_name]
            if not matching_pages:
                errors.append(f"[X] Subpage '{subpage_name}' not found under Engineering Wiki")
            else:
                checks_passed.append(f"[C] Subpage '{subpage_name}' found under Engineering Wiki")
            found_subpages[subpage_name] = matching_pages[0]
    
        # 4. Verify each subpage has required structure
        for subpage_name, subpage in found_subpages.items():
            subpage_id = subpage.get("_id")
            blocks = _get_blocks_for_page(backend, subpage_id)
        
            if not blocks:
                errors.append(f"[X] Subpage '{subpage_name}' has no content blocks")
            else:
                checks_passed.append(f"[C] Subpage '{subpage_name}' has content blocks")
        
            # Check for required block types
            block_types = [block.get("type") for block in blocks]

            if "heading1" not in block_types:
                errors.append(f"[X] Subpage '{subpage_name}' missing heading1 block")
            else:
                checks_passed.append(f"[C] Subpage '{subpage_name}' has heading1 block")

            if "paragraph" not in block_types:
                errors.append(f"[X] Subpage '{subpage_name}' missing paragraph block")
            else:
                checks_passed.append(f"[C] Subpage '{subpage_name}' has paragraph block")

            if "divider" not in block_types:
                errors.append(f"[X] Subpage '{subpage_name}' missing divider block")
            else:
                checks_passed.append(f"[C] Subpage '{subpage_name}' has divider block")

            # Check for additional headings (heading2 or heading3)
            has_additional_heading = any(bt in ["heading2", "heading3"] for bt in block_types)
            if not has_additional_heading:
                errors.append(f"[X] Subpage '{subpage_name}' missing additional heading blocks")
            else:
                checks_passed.append(f"[C] Subpage '{subpage_name}' has additional heading blocks")

        # 5. Check parent wiki has table of contents with bulleted list
        wiki_blocks = _get_blocks_for_page(backend, wiki_page_id)

        if not wiki_blocks:
            errors.append("[X] Engineering Wiki has no content blocks")
        else:
            checks_passed.append("[C] Engineering Wiki has content blocks")

        has_bulleted_list = any(block.get("type") == "bulletedList" for block in wiki_blocks)

        if not has_bulleted_list:
            errors.append("[X] Engineering Wiki missing bulletedList table of contents")
        else:
            checks_passed.append("[C] Engineering Wiki has bulletedList table of contents")
    
        # 6. Verify total of 4 child pages (could be 3 new + 1 existing, or just check >= 3)
        if len(child_pages) < 3:
            errors.append(f"[X] Engineering Wiki has only {len(child_pages)} child pages, expected at least 3")
        else:
            checks_passed.append(f"[C] Engineering Wiki has only {len(child_pages)} child pages, expected at least 3")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

    

    # -----------------------------------------------------------------------------
    # reorganize-engineering-documentation-v2
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_restructure_engineering_documentation(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Initial State: 
    Verification: 
    
    Product: 
    Task: 
    """
    errors: list[str] = []
    checks_passed: list[str] = []

# -----------------------------------------------------------------------------
# consolidate-architecture-docs-v2
# -----------------------------------------------------------------------------
def _validate_agent_consolidate_architecture_docs(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Task: Consolidate architecture documentation into a top-level hub.

    Validates:
    1. "System Architecture Hub" page exists with building icon
    2. Hub is marked as favorite
    3. Architecture page and its child pages moved under the hub
    4. Hub contains overview section with heading blocks and bullet list blocks
    5. Original nested structure preserved
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    # Get all pages to search through
    try:
        all_pages = backend.query({
            "collection": "pages",
            "filter": {}
        })

        if not all_pages:
            errors.append("[X] No pages found in backend")
        else:
            checks_passed.append("[C] pages found in backend")

        if not isinstance(all_pages, list):
            all_pages = [all_pages]

        # 1. Find "System Architecture Hub" page (flexible matching)
        hub_page = None
        for page in all_pages:
            title = page.get("title", "")
            if "System Architecture Hub" in title or title == "System Architecture Hub":
                hub_page = page
                break

        if not hub_page:
            errors.append("[X] Page 'System Architecture Hub' not found")
        else:
            checks_passed.append("[C] Page 'System Architecture Hub' found")

        hub_page_id = hub_page.get("_id")

        if not hub_page_id:
            errors.append("[X] System Architecture Hub page has no _id")
        else:
            checks_passed.append("[C] System Architecture Hub page has _id")

        # Check for building icon (various building emojis)
        icon = hub_page.get("icon")
        building_icons = ["🏢", "🏗️", "🏛️", "\U0001f3e2", "\U0001f3d7\ufe0f", "\U0001f3d7", "\U0001f3db\ufe0f", "\U0001f3db"]
        if not icon or icon not in building_icons:
            errors.append(f"[X] System Architecture Hub does not have a building icon (found: {icon!r})")
        else:
            checks_passed.append(f"[C] System Architecture Hub has a building icon (found: {icon!r})")

        # 2. Check if hub is marked as favorite
        if not hub_page.get("isFavorite"):
            errors.append("[X] System Architecture Hub is not marked as favorite")
        else:
            checks_passed.append("[C] System Architecture Hub is marked as favorite")

        # 3. Find "Architecture" page and verify it's under the hub
        architecture_page = None
        for page in all_pages:
            title = page.get("title", "")
            # Match "Architecture" but not "System Architecture Hub"
            if title == "Architecture" or (title.endswith("Architecture") and "Hub" not in title and "Frontend" not in title):
                architecture_page = page
                break

        if not architecture_page:
            errors.append("[X] Architecture page not found")
        else:
            checks_passed.append("[C] Architecture page found")

        architecture_page_id = architecture_page.get("_id")

        if architecture_page.get("parentId") != hub_page_id:
            errors.append("[X] Architecture page is not under System Architecture Hub")
        else:
            checks_passed.append("[C] Architecture page is under System Architecture Hub")

        # 4. Verify child pages of Architecture are preserved (Frontend Architecture, Component Library, etc.)
        child_pages = [p for p in all_pages if p.get("parentId") == architecture_page_id]

        # We just check that there are child pages preserved, not specific ones
        if len(child_pages) == 0:
            errors.append("[X] Architecture page has no child pages - nested structure may not be preserved")
        else:
            checks_passed.append("[C] Architecture page has child pages - nested structure preserved")

        # 5. Verify hub has overview section with headings and bullet list
        hub_blocks = _get_blocks_for_page(backend, hub_page_id)

        if not hub_blocks:
            errors.append("[X] System Architecture Hub has no content blocks")
        else:
            checks_passed.append("[C] System Architecture Hub has content blocks")

        block_types = [block.get("type") for block in hub_blocks]

        # Check for heading blocks
        has_heading = any(bt in ["heading1", "heading2", "heading3"] for bt in block_types)
        if not has_heading:
            errors.append("[X] System Architecture Hub missing heading blocks in overview")
        else:
            checks_passed.append("[C] System Architecture Hub has heading blocks in overview")

        # Check for bullet list blocks
        has_bullet_list = any(bt in ["bulletedList", "bulleted_list"] for bt in block_types)
        if not has_bullet_list:
            errors.append("[X] System Architecture Hub missing bullet list blocks describing architectural areas")
        else:
            checks_passed.append("[C] System Architecture Hub has bullet list blocks describing architectural areas")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Registry of all V2 Reward Functions
# =============================================================================
def _validate_agent_create_documentation_overview_map(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate that the agent created a comprehensive documentation overview map.
    
    Success criteria:
    1. Documentation Overview page exists as sibling of Project Documentation
    2. Page has correct structure with heading_1 "Complete Documentation Map"
    3. Contains heading_2 "Documentation Structure" section
    4. Has heading_3 entries for each top-level child of Project Documentation
    5. Toggle blocks present for pages with children, containing bulleted lists
    6. Statistics section with heading_2 "Documentation Statistics"
    7. Callout block with gray background and chart icon containing page count, depth, and date
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    try:
        try:
            # Find Project Documentation page
            proj_docs_pages = _get_pages(backend, "Project Documentation")
        
            if not proj_docs_pages:
                errors.append("[X] Project Documentation page not found")
            else:
                checks_passed.append("[C] Project Documentation page found")
        
            proj_docs_page = proj_docs_pages[0]
            proj_docs_parent_id = proj_docs_page.get("parentId") or proj_docs_page.get("parent_id")
        
            # Find Documentation Overview page
            overview_pages = _get_pages(backend, "Documentation Overview")
        
            if not overview_pages:
                errors.append("[X] Documentation Overview page not found")
            else:
                checks_passed.append("[C] Documentation Overview page found")
        
            overview_page = overview_pages[0]
            overview_page_id = overview_page.get("_id")
            overview_parent_id = overview_page.get("parentId") or overview_page.get("parent_id")

            # Check if Documentation Overview is sibling of Project Documentation
            if overview_parent_id != proj_docs_parent_id:
                errors.append("[X] Documentation Overview is not a sibling of Project Documentation (different parent)")
            else:
                checks_passed.append("[C] Documentation Overview is a sibling of Project Documentation (different parent)")

            # Get blocks from Documentation Overview page
            blocks = _get_blocks_for_page(backend, overview_page_id)
            if not blocks:
                errors.append("[X] Documentation Overview page has no content blocks")
            else:
                checks_passed.append("[C] Documentation Overview page has content blocks")
        
            # Check for heading_1 with "Complete Documentation Map"
            has_main_heading = False
            has_structure_heading = False
            has_statistics_heading = False
            has_heading3 = False
            has_toggle_block = False
            has_bulleted_list_with_prefix = False
            has_callout = False
        
            for block in blocks:
                block_type = block.get("type", "")
                content = block.get("content", "")
            
                if block_type == "heading1" and "Complete Documentation Map" in content:
                    has_main_heading = True
            
                if block_type == "heading2" and "Documentation Structure" in content:
                    has_structure_heading = True
            
                if block_type == "heading2" and "Documentation Statistics" in content:
                    has_statistics_heading = True
            
                if block_type == "heading3" and "📁" in content:
                    has_heading3 = True
            
                if block_type == "toggle":
                    has_toggle_block = True
                    # Check if toggle has bulleted list children
                    toggle_children = block.get("children", [])
                    for child in toggle_children:
                        if child.get("type") == "bulletedList" and "└─" in child.get("content", ""):
                            has_bulleted_list_with_prefix = True
            
                if block_type == "callout":
                    properties = block.get("properties", {})
                    bg_color = properties.get("backgroundColor", "")
                    icon = properties.get("icon", "")
                
                    if ("gray" in bg_color.lower() and 
                        "📈" in icon and 
                        "Total documentation pages:" in content and
                        "Maximum nesting depth:" in content and
                        "Last comprehensive update:" in content):
                        has_callout = True
        
            # Check all requirements
            missing = []
            if not has_main_heading:
                missing.append("heading_1 'Complete Documentation Map'")
            if not has_structure_heading:
                missing.append("heading_2 'Documentation Structure'")
            if not has_heading3:
                missing.append("heading_3 entries with 📁 emoji")
            if not has_toggle_block:
                missing.append("toggle blocks for sub-sections")
            if not has_bulleted_list_with_prefix:
                missing.append("bulleted lists with '└─' prefix in toggles")
            if not has_statistics_heading:
                missing.append("heading_2 'Documentation Statistics'")
            if not has_callout:
                missing.append("statistics callout with gray background, chart icon, and required content")
        
            if missing:
                errors.append(f"[X] Documentation Overview is missing: {', '.join(missing)}")
            else:
                checks_passed.append(f"[C] Documentation Overview is has")
        
            return TaskScore(
                score=1.0 if len(errors) == 0 else 0.0,
                metadata=ScoreMetadata(
                    success_accumulator=list(dict.fromkeys(checks_passed)),
                    error_accumulator=list(dict.fromkeys(errors)),
                )
            )
        
        except Exception as e:
            errors.append(f"[X] Error validating documentation overview: {str(e)}")
            return TaskScore(
                score=0.0,
                metadata=ScoreMetadata(
                    success_accumulator=list(dict.fromkeys(checks_passed)),
                    error_accumulator=list(dict.fromkeys(errors)),
                )
            )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_agent_create_meeting_analytics_hub(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate that the agent created a Meeting Analytics Hub with comprehensive analysis.
    
    Success criteria:
    1. Meeting Analytics Hub page exists as child of Meeting Notes
    2. Contains heading1 "📊 Meeting Analytics Hub"
    3. Has quote block with overview text
    4. Meeting Overview section with blue callout containing meeting count and date range
    5. Each meeting has heading3 with icon/title and analysis (agenda, actions, decisions)
    6. Aggregate Insights section with markdown code block containing summary table
    7. Ends with toggle containing numbered recommendations
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    try:
        try:
            # Find Meeting Notes page
            meeting_notes_pages = _get_pages(backend, "Meeting Notes")
        
            if not meeting_notes_pages:
                errors.append("[X] Meeting Notes page not found")
            else:
                checks_passed.append("[C] Meeting Notes page found")
        
            meeting_notes_page = meeting_notes_pages[0]
            meeting_notes_id = meeting_notes_page.get("_id")
        
            # Find Meeting Analytics Hub page
            analytics_pages = _get_pages(backend, "Meeting Analytics Hub")
        
            if not analytics_pages:
                errors.append("[X] Meeting Analytics Hub page not found")
            else:
                checks_passed.append("[C] Meeting Analytics Hub page found")
        
            analytics_page = analytics_pages[0]
            analytics_page_id = analytics_page.get("_id")
            analytics_parent_id = analytics_page.get("parentId") or analytics_page.get("parent_id")

            # Check if Analytics Hub is child of Meeting Notes
            if analytics_parent_id != meeting_notes_id:
                errors.append(f"[X] Meeting Analytics Hub is not a child of Meeting Notes (parent: {analytics_parent_id}, expected: {meeting_notes_id})")
            else:
                checks_passed.append(f"[C] Meeting Analytics Hub is a child of Meeting Notes (parent: {analytics_parent_id}, expected: {meeting_notes_id})")

            # Get blocks from Meeting Analytics Hub page
            blocks = _get_blocks_for_page(backend, analytics_page_id)
            if not blocks:
                errors.append("[X] Meeting Analytics Hub page has no content blocks")
            else:
                checks_passed.append("[C] Meeting Analytics Hub page has content blocks")
        
            # Validate required components
            has_main_heading = False
            has_quote_block = False
            has_overview_heading = False
            has_blue_callout = False
            has_meeting_heading3 = False
            has_analysis_paragraph = False
            has_analysis_bulleted_list = False
            has_insights_heading = False
            has_markdown_code_block = False
            has_toggle_recommendations = False
            has_numbered_list_in_toggle = False
        
            for block in blocks:
                block_type = block.get("type", "")
                content = block.get("content", "")
                properties = block.get("properties", {})
            
                # Check heading1
                if block_type == "heading1" and "Meeting Analytics Hub" in content and "📊" in content:
                    has_main_heading = True
            
                # Check quote block
                if block_type == "quote" and "Comprehensive analysis" in content:
                    has_quote_block = True
            
                # Check Meeting Overview heading
                if block_type == "heading2" and "Meeting Overview" in content:
                    has_overview_heading = True
            
                # Check blue callout with calendar icon
                if block_type == "callout":
                    bg_color = properties.get("backgroundColor", "")
                    icon = properties.get("icon", "")
                    if ("blue" in bg_color.lower() and 
                        "📅" in icon and 
                        "Total meetings tracked:" in content):
                        has_blue_callout = True
            
                # Check heading3 for meetings (should have icon and title)
                if block_type == "heading3" and any(emoji in content for emoji in ["📅", "📋", "💼", "🗓️"]):
                    has_meeting_heading3 = True
            
                # Check analysis paragraphs
                if block_type == "paragraph" and ("Date:" in content or "Not specified" in content):
                    has_analysis_paragraph = True
            
                # Check analysis bulleted lists
                if block_type == "bulletedList" and any(x in content for x in ["Total agenda items:", "Action items:", "Decisions made:"]):
                    has_analysis_bulleted_list = True
            
                # Check Aggregate Insights heading
                if block_type == "heading2" and "Aggregate Insights" in content:
                    has_insights_heading = True
            
                # Check markdown code block
                if block_type == "code":
                    lang = properties.get("language", "")
                    if lang == "markdown" and "| Metric | Value |" in content:
                        has_markdown_code_block = True
            
                # Check toggle for recommendations
                if block_type == "toggle" and "Recommendations" in content:
                    has_toggle_recommendations = True
                    # Check if toggle has numbered list children
                    toggle_children = block.get("children", [])
                    for child in toggle_children:
                        if child.get("type") == "numberedList":
                            has_numbered_list_in_toggle = True
        
            # Check all requirements
            missing = []
            if not has_main_heading:
                missing.append("heading1 '📊 Meeting Analytics Hub'")
            if not has_quote_block:
                missing.append("quote block with overview text")
            if not has_overview_heading:
                missing.append("heading2 'Meeting Overview'")
            if not has_blue_callout:
                missing.append("blue callout with calendar icon and meeting count")
            if not has_meeting_heading3:
                missing.append("heading3 entries with icons for meetings")
            if not has_analysis_paragraph:
                missing.append("analysis paragraphs with date info")
            if not has_analysis_bulleted_list:
                missing.append("bulleted lists with agenda/action/decision counts")
            if not has_insights_heading:
                missing.append("heading2 'Aggregate Insights'")
            if not has_markdown_code_block:
                missing.append("markdown code block with summary table")
            if not has_toggle_recommendations:
                missing.append("toggle block with recommendations")
            if not has_numbered_list_in_toggle:
                missing.append("numbered list inside toggle")
        
            if missing:
                errors.append(f"[X] Meeting Analytics Hub is missing: {', '.join(missing)}")
            else:
                checks_passed.append(f"[C] Meeting Analytics Hub is has")
        
            return TaskScore(
                score=1.0 if len(errors) == 0 else 0.0,
                metadata=ScoreMetadata(
                    success_accumulator=list(dict.fromkeys(checks_passed)),
                    error_accumulator=list(dict.fromkeys(errors)),
                )
            )
        
        except Exception as e:
            errors.append(f"[X] Error validating meeting analytics hub: {str(e)}")
            return TaskScore(
                score=0.0,
                metadata=ScoreMetadata(
                    success_accumulator=list(dict.fromkeys(checks_passed)),
                    error_accumulator=list(dict.fromkeys(errors)),
                )
            )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_agent_create_design_system_catalog(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate that the agent created a Design System Components Catalog with detailed analysis.
    
    Success criteria:
    1. Catalog page exists as child of Design System
    2. Contains heading1 "🎨 Design System Components Catalog"
    3. Has purple callout with magnifying glass icon showing today's date and component counts
    4. Each child page has heading3 with icon/title
    5. Toggle blocks for each component with block type counts
    6. Quick Links section with bookmark blocks for each child page
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    try:
        try:
            # Find Design System page
            design_system_pages = _get_pages(backend, "Design System")
        
            if not design_system_pages:
                errors.append("[X] Design System page not found")
            else:
                checks_passed.append("[C] Design System page found")
        
            design_system_page = design_system_pages[0]
            design_system_id = design_system_page.get("_id")
        
            # Find Design System Components Catalog page
            catalog_pages = _get_pages(backend, "Design System Components Catalog")
        
            if not catalog_pages:
                errors.append("[X] Design System Components Catalog page not found")
            else:
                checks_passed.append("[C] Design System Components Catalog page found")
        
            catalog_page = catalog_pages[0]
            catalog_page_id = catalog_page.get("_id")
            catalog_parent_id = catalog_page.get("parentId") or catalog_page.get("parent_id")

            # Check if Catalog is child of Design System
            if catalog_parent_id != design_system_id:
                errors.append(f"[X] Catalog is not a child of Design System (parent: {catalog_parent_id}, expected: {design_system_id})")
            else:
                checks_passed.append(f"[C] Catalog is a child of Design System (parent: {catalog_parent_id}, expected: {design_system_id})")

            # Get blocks from Catalog page
            blocks = _get_blocks_for_page(backend, catalog_page_id)
            if not blocks:
                errors.append("[X] Catalog page has no content blocks")
            else:
                checks_passed.append("[C] Catalog page has content blocks")
        
            # Validate required components
            has_main_heading = False
            has_purple_callout = False
            has_categories_heading = False
            has_component_heading3 = False
            has_toggle_blocks = False
            has_numbered_list_in_toggle = False
            has_quick_links_heading = False
            has_bookmark_blocks = False
        
            for block in blocks:
                block_type = block.get("type", "")
                content = block.get("content", "")
                properties = block.get("properties", {})
            
                # Check heading1
                if block_type == "heading1" and "Design System Components Catalog" in content and "🎨" in content:
                    has_main_heading = True
            
                # Check purple callout with magnifying glass icon
                if block_type == "callout":
                    bg_color = properties.get("backgroundColor", "")
                    icon = properties.get("icon", "")
                    if ("purple" in bg_color.lower() and 
                        "🔍" in icon and 
                        "Last updated:" in content and
                        "Total components documented:" in content and
                        "Total documentation blocks:" in content):
                        has_purple_callout = True
            
                # Check Component Categories heading
                if block_type == "heading2" and "Component Categories" in content:
                    has_categories_heading = True
            
                # Check heading3 for components (should have emoji/icon)
                if block_type == "heading3" and len(content) > 0:
                    has_component_heading3 = True
            
                # Check toggle blocks
                if block_type == "toggle" and "View Details" in content:
                    has_toggle_blocks = True
                    # Check if toggle has numbered list children
                    toggle_children = block.get("children", [])
                    for child in toggle_children:
                        if child.get("type") == "numberedList" and "Documentation blocks:" in child.get("content", ""):
                            has_numbered_list_in_toggle = True
            
                # Check Quick Links heading
                if block_type == "heading2" and "Quick Links" in content:
                    has_quick_links_heading = True
            
                # Check bookmark blocks
                if block_type == "bookmark":
                    caption = properties.get("caption", "")
                    if "Navigate to component documentation" in caption:
                        has_bookmark_blocks = True
        
            # Check all requirements
            missing = []
            if not has_main_heading:
                missing.append("heading1 '🎨 Design System Components Catalog'")
            if not has_purple_callout:
                missing.append("purple callout with magnifying glass icon and counts")
            if not has_categories_heading:
                missing.append("heading2 'Component Categories'")
            if not has_component_heading3:
                missing.append("heading3 entries for components")
            if not has_toggle_blocks:
                missing.append("toggle blocks with 'View Details'")
            if not has_numbered_list_in_toggle:
                missing.append("numbered list inside toggle with block counts")
            if not has_quick_links_heading:
                missing.append("heading2 'Quick Links'")
            if not has_bookmark_blocks:
                missing.append("bookmark blocks with navigation captions")
        
            if missing:
                errors.append(f"[X] Catalog is missing: {', '.join(missing)}")
            else:
                checks_passed.append(f"[C] Catalog is has")
        
            return TaskScore(
                score=1.0 if len(errors) == 0 else 0.0,
                metadata=ScoreMetadata(
                    success_accumulator=list(dict.fromkeys(checks_passed)),
                    error_accumulator=list(dict.fromkeys(errors)),
                )
            )
        
        except Exception as e:
            errors.append(f"[X] Error validating design system catalog: {str(e)}")
            return TaskScore(
                score=0.0,
                metadata=ScoreMetadata(
                    success_accumulator=list(dict.fromkeys(checks_passed)),
                    error_accumulator=list(dict.fromkeys(errors)),
                )
            )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_agent_add_document_structure_overview(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate that the agent added a document structure overview section before Technical Requirements.
    
    Success criteria:
    1. New section appears before Technical Requirements with divider first
    2. heading2 "📑 Document Structure Overview" present
    3. Purple callout with magnifying glass icon listing sections with subsection counts
    4. Bold paragraph showing total sections and subsections
    5. Toggle block with navigation tips
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    try:
        try:
            # Find Comprehensive Product Requirements Document page
            prd_pages = _get_pages(backend, "Comprehensive Product Requirements Document")
        
            if not prd_pages:
                errors.append("[X] Comprehensive Product Requirements Document page not found")
            else:
                checks_passed.append("[C] Comprehensive Product Requirements Document page found")
        
            prd_page = prd_pages[0]
            prd_page_id = prd_page.get("_id")

            # Get blocks from PRD page
            blocks = _get_blocks_for_page(backend, prd_page_id)
            if not blocks:
                errors.append("[X] PRD page has no content blocks")
            else:
                checks_passed.append("[C] PRD page has content blocks")
        
            # Find Technical Requirements heading and the structure overview section
            tech_req_index = -1
            overview_section_start = -1
        
            for i, block in enumerate(blocks):
                if block.get("type") == "heading2" and "Technical Requirements" in block.get("content", ""):
                    tech_req_index = i
                if block.get("type") == "heading2" and "Document Structure Overview" in block.get("content", ""):
                    overview_section_start = i
        
            if tech_req_index == -1:
                errors.append("[X] Technical Requirements heading not found")
            else:
                checks_passed.append("[C] Technical Requirements heading found")
        
            if overview_section_start == -1:
                errors.append("[X] Document Structure Overview section not found")
            else:
                checks_passed.append("[C] Document Structure Overview section found")
        
            # Verify overview section appears BEFORE Technical Requirements
            if overview_section_start >= tech_req_index:
                errors.append(f"[X] Document Structure Overview must appear BEFORE Technical Requirements (found at index {overview_section_start}, Technical Requirements at {tech_req_index})")
            else:
                checks_passed.append(f"[C] Document Structure Overview must appear BEFORE Technical Requirements (found at index {overview_section_start}, Technical Requirements at {tech_req_index})")
        
            # Validate components in the overview section
            has_divider_before = False
            has_overview_heading = False
            has_purple_callout = False
            has_numbered_list_in_callout = False
            has_bold_paragraph_totals = False
            has_toggle_tips = False
        
            # Check blocks from overview section start to tech requirements
            section_blocks = blocks[max(0, overview_section_start-1):tech_req_index]
        
            for i, block in enumerate(section_blocks):
                block_type = block.get("type", "")
                content = block.get("content", "")
                properties = block.get("properties", {})
            
                # Check for divider before overview heading
                if i < len(section_blocks) - 1:
                    next_block = section_blocks[i + 1]
                    if (block_type == "divider" and 
                        next_block.get("type") == "heading2" and 
                        "Document Structure Overview" in next_block.get("content", "")):
                        has_divider_before = True
            
                # Check overview heading
                if block_type == "heading2" and "Document Structure Overview" in content and "📑" in content:
                    has_overview_heading = True
            
                # Check purple callout
                if block_type == "callout":
                    bg_color = properties.get("backgroundColor", "")
                    icon = properties.get("icon", "")
                    if "purple" in bg_color.lower() and "🔍" in icon:
                        has_purple_callout = True
                        # Check if callout contains numbered list as children
                        callout_children = block.get("children", [])
                        for child in callout_children:
                            if child.get("type") == "numberedList" and "subsections" in child.get("content", ""):
                                has_numbered_list_in_callout = True
            
                # Check bold paragraph with totals
                if block_type == "paragraph":
                    is_bold = properties.get("bold", False)
                    if is_bold and "Total sections:" in content and "Total subsections:" in content:
                        has_bold_paragraph_totals = True
            
                # Check toggle with navigation tips
                if block_type == "toggle" and "Quick Navigation Tips" in content:
                    has_toggle_tips = True
                    # Verify toggle contains the navigation tip text
                    toggle_children = block.get("children", [])
                    has_nav_tip_text = any(
                        "Ctrl/Cmd + F" in child.get("content", "") 
                        for child in toggle_children
                    )
                    if not has_nav_tip_text:
                        errors.append("[X] Toggle block missing navigation tip text")
                    else:
                        checks_passed.append("[C] Toggle block has navigation tip text")
        
            # Check all requirements
            missing = []
            if not has_divider_before:
                missing.append("divider before overview section")
            if not has_overview_heading:
                missing.append("heading2 '📑 Document Structure Overview'")
            if not has_purple_callout:
                missing.append("purple callout with 🔍 icon")
            if not has_numbered_list_in_callout:
                missing.append("numbered list in callout showing subsection counts")
            if not has_bold_paragraph_totals:
                missing.append("bold paragraph with section/subsection totals")
            if not has_toggle_tips:
                missing.append("toggle block with navigation tips")
        
            if missing:
                errors.append(f"[X] Document Structure Overview section is missing: {', '.join(missing)}")
            else:
                checks_passed.append(f"[C] Document Structure Overview section is has")
        
            return TaskScore(
                score=1.0 if len(errors) == 0 else 0.0,
                metadata=ScoreMetadata(
                    success_accumulator=list(dict.fromkeys(checks_passed)),
                    error_accumulator=list(dict.fromkeys(errors)),
                )
            )
        
        except Exception as e:
            errors.append(f"[X] Error validating document structure overview: {str(e)}")
            return TaskScore(
                score=0.0,
                metadata=ScoreMetadata(
                    success_accumulator=list(dict.fromkeys(checks_passed)),
                    error_accumulator=list(dict.fromkeys(errors)),
                )
            )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_agent_add_sprint_goals_alignment(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate that the agent added a Sprint Goals Alignment section in the correct position.
    
    Success criteria:
    1. Section positioned between 'What I plan to do next week' and 'Blockers'
    2. heading2 "🎯 Sprint Goals Alignment" present
    3. Paragraph with exact text about tracking alignment
    4. Three unchecked to-do blocks with specific text and emojis
    5. Quote block with calculated percentages based on all todos
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    try:
        try:
            # Find Weekly Standup Template page
            template_pages = _get_pages(backend, "Weekly Standup Template")

            if not template_pages:
                errors.append("[X] Weekly Standup Template page not found")
            else:
                checks_passed.append("[C] Weekly Standup Template page found")

            template_page = template_pages[0]
            page_id = template_page.get("_id")

            if not page_id:
                errors.append("[X] Weekly Standup Template page has no _id")
            else:
                checks_passed.append("[C] Weekly Standup Template page has _id")

            # Get blocks from blocks collection (not embedded in page)
            blocks = _get_blocks(backend, page_id)
            if not blocks:
                errors.append("[X] Template page has no content blocks")
            else:
                checks_passed.append("[C] Template page has content blocks")
        
            # Find key section positions
            next_week_index = -1
            blockers_index = -1
            sprint_goals_index = -1
        
            for i, block in enumerate(blocks):
                content = block.get("content", "")
                block_type = block.get("type", "")
            
                if "What I plan to do next week" in content:
                    next_week_index = i
                if "Blockers" in content and block_type == "heading2":
                    blockers_index = i
                if block_type == "heading2" and "Sprint Goals Alignment" in content:
                    sprint_goals_index = i
        
            if next_week_index == -1:
                errors.append("[X] 'What I plan to do next week' section not found")
            else:
                checks_passed.append("[C] 'What I plan to do next week' section found")
        
            if blockers_index == -1:
                errors.append("[X] 'Blockers' section not found")
            else:
                checks_passed.append("[C] 'Blockers' section found")
        
            if sprint_goals_index == -1:
                errors.append("[X] 'Sprint Goals Alignment' section not found")
            else:
                checks_passed.append("[C] 'Sprint Goals Alignment' section found")
        
            # Verify positioning: Sprint Goals must be between next week and blockers
            if not (next_week_index < sprint_goals_index < blockers_index):
                errors.append(f"[X] Sprint Goals Alignment section is not positioned between 'What I plan to do next week' (index {next_week_index}) and 'Blockers' (index {blockers_index}). Found at index {sprint_goals_index}")
            else:
                checks_passed.append(f"[C] Sprint Goals Alignment section is positioned between 'What I plan to do next week' (index {next_week_index}) and 'Blockers' (index {blockers_index}). Found at index {sprint_goals_index}")
        
            # Validate components in the Sprint Goals section
            has_sprint_goals_heading = False
            has_exact_paragraph = False
            has_three_todos = False
            has_quote_with_percentages = False
        
            todos_found = []
            expected_todos = [
                "🔄 Update progress on assigned sprint goals",
                "📊 Log time estimates vs actual for completed tasks",
                "🤝 Identify dependencies with other team members"
            ]
        
            # Check blocks from Sprint Goals section to Blockers section
            section_blocks = blocks[sprint_goals_index:blockers_index]
        
            for block in section_blocks:
                block_type = block.get("type", "")
                content = block.get("content", "")
                properties = block.get("properties", {})
            
                # Check heading
                if block_type == "heading2" and "Sprint Goals Alignment" in content and "🎯" in content:
                    has_sprint_goals_heading = True
            
                # Check exact paragraph text
                if block_type == "paragraph" and content == "Track how your work aligns with current sprint objectives:":
                    has_exact_paragraph = True
            
                # Check to-do blocks
                if block_type == "todo":
                    checked = properties.get("checked", True)
                    if any(expected_todo in content for expected_todo in expected_todos):
                        if not checked:  # Must be unchecked
                            todos_found.append(content)
            
                # Check quote block with percentages
                if block_type == "quote":
                    if ("Template usage:" in content and 
                        "% of tasks completed" in content and
                        "% in progress" in content and
                        "% blocked" in content):
                        has_quote_with_percentages = True
        
            # Verify exactly 3 todos found
            if len(todos_found) == 3:
                # Check all expected todos are present
                all_present = all(
                    any(expected in found for found in todos_found)
                    for expected in expected_todos
                )
                if all_present:
                    has_three_todos = True
        
            # Check all requirements
            missing = []
            if not has_sprint_goals_heading:
                missing.append("heading2 '🎯 Sprint Goals Alignment'")
            if not has_exact_paragraph:
                missing.append("paragraph with exact text 'Track how your work aligns with current sprint objectives:'")
            if not has_three_todos:
                missing.append(f"three unchecked to-do blocks with exact text and emojis (found {len(todos_found)})")
            if not has_quote_with_percentages:
                missing.append("quote block with calculated percentages")
        
            if missing:
                errors.append(f"[X] Sprint Goals Alignment section is missing: {', '.join(missing)}")
            else:
                checks_passed.append(f"[C] Sprint Goals Alignment section is has")
        
            return TaskScore(
                score=1.0 if len(errors) == 0 else 0.0,
                metadata=ScoreMetadata(
                    success_accumulator=list(dict.fromkeys(checks_passed)),
                    error_accumulator=list(dict.fromkeys(errors)),
                )
            )

        except Exception as e:
            errors.append(f"[X] Error validating sprint goals alignment: {str(e)}")
            return TaskScore(
                score=0.0,
                metadata=ScoreMetadata(
                    success_accumulator=list(dict.fromkeys(checks_passed)),
                    error_accumulator=list(dict.fromkeys(errors)),
                )
            )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_agent_reorganize_external_resources_3(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate that the agent reorganized the External Resources & Links page.

    Success criteria:
    1. heading_1 is '🔗 External Resources Hub'
    2. Italic paragraph with date and accurate bookmark count
    3. Three heading_2 sections: '📚 Documentation Links', '🛠️ Tools & Services', '📰 Industry News'
    4. Bookmark blocks organized under appropriate categories
    5. Purple callout at end with 🎯 icon and specific text
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    try:
        try:
            # Find External Resources & Links page
            resources_pages = _get_pages(backend, "External Resources & Links")

            if not resources_pages:
                errors.append("[X] External Resources & Links page not found")
            else:
                checks_passed.append("[C] External Resources & Links page found")

            resources_page = resources_pages[0]
            page_id = resources_page.get("_id")

            if not page_id:
                errors.append("[X] External Resources & Links page has no _id")
            else:
                checks_passed.append("[C] External Resources & Links page has _id")

            # Get blocks from blocks collection
            blocks = _get_blocks(backend, page_id)
            if not blocks:
                errors.append("[X] External Resources page has no content blocks")
            else:
                checks_passed.append("[C] External Resources page has content blocks")

            # Count bookmark blocks for validation
            bookmark_count = sum(1 for b in blocks if b.get("type") == "bookmark")

            # Validate required components
            has_hub_heading = False
            has_italic_paragraph = False
            has_correct_bookmark_count = False
            has_documentation_section = False
            has_tools_section = False
            has_news_section = False
            has_purple_callout = False
            has_callout_text = False

            # Track section order and positions
            section_positions = {}

            for i, block in enumerate(blocks):
                block_type = block.get("type", "")
                content = block.get("content", "")
                properties = block.get("properties", {})

                # Check heading_1 with hub title
                if block_type == "heading1" and "External Resources Hub" in content and "🔗" in content:
                    has_hub_heading = True

                # Check italic paragraph with date and resource count
                if block_type == "paragraph":
                    is_italic = properties.get("italic", False)
                    if is_italic and "Last updated:" in content and ("Total resources:" in content or "Total bookmarks:" in content):
                        has_italic_paragraph = True
                        # Check if bookmark count is accurate (allow some flexibility)
                        if str(bookmark_count) in content or f"{bookmark_count}" in content:
                            has_correct_bookmark_count = True

                # Check for three heading_2 sections
                if block_type == "heading2":
                    if "Documentation Links" in content and "📚" in content:
                        has_documentation_section = True
                        section_positions["documentation"] = i
                    if "Tools & Services" in content and "🛠️" in content:
                        has_tools_section = True
                        section_positions["tools"] = i
                    if "Industry News" in content and "📰" in content:
                        has_news_section = True
                        section_positions["news"] = i

                # Check for purple callout at end with specific text
                if block_type == "callout":
                    bg_color = properties.get("backgroundColor", "")
                    icon = properties.get("icon", "")
                    if "purple" in bg_color.lower() and "🎯" in icon:
                        has_purple_callout = True
                        if "Pro tip:" in content and "Star your most-used resources" in content:
                            has_callout_text = True

            # Verify callout is at the end (one of the last few blocks)
            callout_at_end = False
            for block in blocks[-3:]:  # Check last 3 blocks
                if block.get("type") == "callout":
                    callout_at_end = True
                    break

            # Verify section order: documentation < tools < news
            section_order_correct = True
            if section_positions:
                doc_pos = section_positions.get("documentation", float('inf'))
                tools_pos = section_positions.get("tools", float('inf'))
                news_pos = section_positions.get("news", float('inf'))
                if not (doc_pos < tools_pos < news_pos):
                    section_order_correct = False

            # Check all requirements
            missing = []
            if not has_hub_heading:
                missing.append("heading_1 '🔗 External Resources Hub'")
            if not has_italic_paragraph:
                missing.append("italic paragraph with 'Last updated' and 'Total resources/bookmarks'")
            if not has_correct_bookmark_count:
                missing.append(f"accurate bookmark count in paragraph (found {bookmark_count} bookmarks)")
            if not has_documentation_section:
                missing.append("heading_2 '📚 Documentation Links'")
            if not has_tools_section:
                missing.append("heading_2 '🛠️ Tools & Services'")
            if not has_news_section:
                missing.append("heading_2 '📰 Industry News'")
            if not section_order_correct:
                missing.append("correct section order (Documentation -> Tools -> News)")
            if not has_purple_callout:
                missing.append("purple callout with 🎯 icon")
            if not has_callout_text:
                missing.append("callout with 'Pro tip: Star your most-used resources' text")
            if not callout_at_end:
                missing.append("callout positioned at end of page")

            if missing:
                errors.append(f"[X] External Resources reorganization is missing: {', '.join(missing)}")
            else:
                checks_passed.append(f"[C] External Resources reorganization is has")

            return TaskScore(
                score=1.0 if len(errors) == 0 else 0.0,
                metadata=ScoreMetadata(
                    success_accumulator=list(dict.fromkeys(checks_passed)),
                    error_accumulator=list(dict.fromkeys(errors)),
                )
            )

        except Exception as e:
            errors.append(f"[X] Error validating external resources reorganization: {str(e)}")
            return TaskScore(
                score=0.0,
                metadata=ScoreMetadata(
                    success_accumulator=list(dict.fromkeys(checks_passed)),
                    error_accumulator=list(dict.fromkeys(errors)),
                )
            )

    # -----------------------------------------------------------------------------
    # add-advanced-features-checklist-v2
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_add_advanced_features_checklist(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate that the agent added an Advanced Features subsection to the Getting Started page.
    
    Success criteria:
    1. Getting Started page exists
    2. heading_3 '🚀 Advanced Features' exists after 'Share a page with a teammate' todo
    3. Blue callout with '💡' icon containing 'Master these power features to boost productivity'
    4. Three specific unchecked to-do blocks exist
    5. Bold paragraph with accurate unchecked todo count
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    try:
        try:
            # Find Getting Started page
            getting_started_pages = _get_pages(backend, "Getting Started")
        
            if not getting_started_pages:
                errors.append("[X] Getting Started page not found")
            else:
                checks_passed.append("[C] Getting Started page found")
        
            getting_started_page = getting_started_pages[0]
            page_id = getting_started_page.get("_id")
        
            if not page_id:
                errors.append("[X] Getting Started page has no _id")
            else:
                checks_passed.append("[C] Getting Started page has _id")
        
            # Get blocks from blocks collection
            blocks = _get_blocks(backend, page_id)
            if not blocks:
                errors.append("[X] Getting Started page has no content blocks")
            else:
                checks_passed.append("[C] Getting Started page has content blocks")
        
            # Find key positions
            share_page_todo_index = -1
            advanced_features_index = -1
        
            for i, block in enumerate(blocks):
                content = block.get("content", "")
                block_type = block.get("type", "")
            
                if block_type == "todo" and "Share a page with a teammate" in content:
                    share_page_todo_index = i
                if block_type == "heading3" and "Advanced Features" in content and "🚀" in content:
                    advanced_features_index = i
        
            if share_page_todo_index == -1:
                errors.append("[X] 'Share a page with a teammate' todo not found")
            else:
                checks_passed.append("[C] 'Share a page with a teammate' todo found")
        
            if advanced_features_index == -1:
                errors.append("[X] heading_3 '🚀 Advanced Features' not found")
            else:
                checks_passed.append("[C] heading_3 '🚀 Advanced Features' found")
        
            # Verify Advanced Features comes AFTER Share a page todo
            if advanced_features_index <= share_page_todo_index:
                errors.append(f"[X] '🚀 Advanced Features' heading must appear AFTER 'Share a page with a teammate' todo (found at {advanced_features_index}, todo at {share_page_todo_index})")
            else:
                checks_passed.append(f"[C] '🚀 Advanced Features' heading must appear AFTER 'Share a page with a teammate' todo (found at {advanced_features_index}, todo at {share_page_todo_index})")
        
            # Validate components after Advanced Features heading
            has_blue_callout = False
            has_callout_text = False
            required_todos = [
                "🔄 Set up database views and filters",
                "⌨️ Learn keyboard shortcuts for faster navigation",
                "🤖 Configure automation rules and integrations"
            ]
            found_todos = []
            has_progress_paragraph = False
        
            # Count all unchecked todos on the page
            unchecked_todo_count = 0
            for block in blocks:
                if block.get("type") == "todo":
                    properties = block.get("properties", {})
                    if not properties.get("checked", False):
                        unchecked_todo_count += 1
        
            # Check blocks after Advanced Features heading
            for block in blocks[advanced_features_index:]:
                block_type = block.get("type", "")
                content = block.get("content", "")
                properties = block.get("properties", {})
            
                # Check blue callout with lightbulb icon
                if block_type == "callout":
                    bg_color = properties.get("backgroundColor", "")
                    icon = properties.get("icon", "")
                    if "blue" in bg_color.lower() and "💡" in icon:
                        has_blue_callout = True
                        if "Master these power features to boost productivity" in content:
                            has_callout_text = True
            
                # Check for required todos
                if block_type == "todo":
                    checked = properties.get("checked", True)
                    for required_todo in required_todos:
                        if required_todo in content and not checked:
                            found_todos.append(required_todo)
            
                # Check for bold progress paragraph
                if block_type == "paragraph":
                    is_bold = properties.get("bold", False)
                    if is_bold and "Progress Update:" in content and "features left to explore" in content:
                        has_progress_paragraph = True
                        # Verify the count is accurate
                        if str(unchecked_todo_count) in content:
                            pass  # Count matches
                        else:
                            errors.append(f"[X] Progress Update count doesn't match actual unchecked todos ({unchecked_todo_count})")
        
            # Check all requirements
            missing = []
            if not has_blue_callout:
                missing.append("blue callout with 💡 icon")
            if not has_callout_text:
                missing.append("callout text 'Master these power features to boost productivity'")
        
            missing_todos = [t for t in required_todos if t not in found_todos]
            if missing_todos:
                missing.append(f"unchecked todos: {missing_todos}")
        
            if not has_progress_paragraph:
                missing.append("bold paragraph with 'Progress Update: [X] features left to explore!'")
        
            if missing:
                errors.append(f"[X] Advanced Features section is missing: {', '.join(missing)}")
            else:
                checks_passed.append(f"[C] Advanced Features section is has")
        
            return TaskScore(
                score=1.0 if len(errors) == 0 else 0.0,
                metadata=ScoreMetadata(
                    success_accumulator=list(dict.fromkeys(checks_passed)),
                    error_accumulator=list(dict.fromkeys(errors)),
                )
            )
    
        except Exception as e:
            errors.append(f"[X] Error validating advanced features checklist: {str(e)}")
            return TaskScore(
                score=0.0,
                metadata=ScoreMetadata(
                    success_accumulator=list(dict.fromkeys(checks_passed)),
                    error_accumulator=list(dict.fromkeys(errors)),
                )
            )

    # -----------------------------------------------------------------------------
    # create-team-performance-dashboard-v2
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_create_team_performance_dashboard(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate that the agent created a Team Performance Dashboard with cross-project metrics.
    
    Success criteria:
    1. Team Performance Dashboard page exists as child of Team Directory
    2. Contains heading_1 '👥 Team Performance Dashboard'
    3. Contains heading_2 '📊 Cross-Project Metrics'
    4. Gray callout (no icon) with heading_3 'Weekly Summary' and bulletedList with rates
    5. heading_2 '🏃 Activity Breakdown'
    6. Three toggle blocks for Weekly Standup, Bug Tracker, Feature Requests
    7. heading_2 '🎯 Recommendations' with paragraph identifying lowest completion rate
    
    Expected rates: Weekly Standup (2/5=40%), Bug Tracker (3/6=50%), Feature Requests (1/3=33.3%)
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    try:
        try:
            # Find Team Directory page
            team_dir_pages = _get_pages(backend, "Team Directory")
        
            if not team_dir_pages:
                errors.append("[X] Team Directory page not found")
            else:
                checks_passed.append("[C] Team Directory page found")
        
            team_dir_page = team_dir_pages[0]
            team_dir_id = team_dir_page.get("_id")
        
            # Find Team Performance Dashboard page
            dashboard_pages = _get_pages(backend, "Team Performance Dashboard")
        
            if not dashboard_pages:
                errors.append("[X] Team Performance Dashboard page not found")
            else:
                checks_passed.append("[C] Team Performance Dashboard page found")
        
            dashboard_page = dashboard_pages[0]
            dashboard_parent_id = dashboard_page.get("parentId") or dashboard_page.get("parent_id")
        
            # Check if Dashboard is child of Team Directory
            if dashboard_parent_id != team_dir_id:
                errors.append(f"[X] Team Performance Dashboard is not a child of Team Directory (parent: {dashboard_parent_id}, expected: {team_dir_id})")
            else:
                checks_passed.append(f"[C] Team Performance Dashboard is a child of Team Directory (parent: {dashboard_parent_id}, expected: {team_dir_id})")
        
            # Get blocks from Dashboard page
            page_id = dashboard_page.get("_id")
            blocks = _get_blocks(backend, page_id)
            if not blocks:
                errors.append("[X] Team Performance Dashboard page has no content blocks")
            else:
                checks_passed.append("[C] Team Performance Dashboard page has content blocks")
        
            # Validate required components
            has_main_heading = False
            has_metrics_heading = False
            has_gray_callout = False
            has_weekly_summary_heading = False
            has_rate_bullets = {"standup": False, "bug": False, "feature": False}
            has_activity_heading = False
            has_toggle_standup = False
            has_toggle_bug = False
            has_toggle_feature = False
            has_recommendations_heading = False
            has_recommendations_paragraph = False
        
            for block in blocks:
                block_type = block.get("type", "")
                content = block.get("content", "")
                properties = block.get("properties", {})
            
                # Check heading_1
                if block_type == "heading1" and "Team Performance Dashboard" in content and "👥" in content:
                    has_main_heading = True
            
                # Check heading_2 Cross-Project Metrics
                if block_type == "heading2" and "Cross-Project Metrics" in content and "📊" in content:
                    has_metrics_heading = True
            
                # Check gray callout
                if block_type == "callout":
                    bg_color = properties.get("backgroundColor", "")
                    icon = properties.get("icon", "")
                    if "gray" in bg_color.lower() and (not icon or icon == ""):
                        has_gray_callout = True
                        # Check for nested content (children)
                        children = block.get("children", [])
                        for child in children:
                            child_type = child.get("type", "")
                            child_content = child.get("content", "")
                            if child_type == "heading3" and "Weekly Summary" in child_content:
                                has_weekly_summary_heading = True
                            if child_type == "bulletedList":
                                if "40%" in child_content or "Standup completion rate" in child_content:
                                    has_rate_bullets["standup"] = True
                                if "50%" in child_content or "Bug resolution rate" in child_content:
                                    has_rate_bullets["bug"] = True
                                if "33" in child_content or "Feature implementation rate" in child_content:
                                    has_rate_bullets["feature"] = True
            
                # Check heading_2 Activity Breakdown
                if block_type == "heading2" and "Activity Breakdown" in content and "🏃" in content:
                    has_activity_heading = True
            
                # Check toggle blocks
                if block_type == "toggle":
                    if "Weekly Standup" in content or "Standup" in content:
                        has_toggle_standup = True
                    if "Bug Tracker" in content or "Bug" in content:
                        has_toggle_bug = True
                    if "Feature Requests" in content or "Feature" in content:
                        has_toggle_feature = True
            
                # Check heading_2 Recommendations
                if block_type == "heading2" and "Recommendations" in content and "🎯" in content:
                    has_recommendations_heading = True
            
                # Check recommendations paragraph
                if block_type == "paragraph" and "Feature Requests" in content and ("lowest" in content.lower() or "prioritize" in content.lower()):
                    has_recommendations_paragraph = True
        
            # Check all requirements
            missing = []
            if not has_main_heading:
                missing.append("heading_1 '👥 Team Performance Dashboard'")
            if not has_metrics_heading:
                missing.append("heading_2 '📊 Cross-Project Metrics'")
            if not has_gray_callout:
                missing.append("gray callout with no icon")
            if not has_weekly_summary_heading:
                missing.append("heading_3 'Weekly Summary' inside callout")
            if not all(has_rate_bullets.values()):
                missing_rates = [k for k, v in has_rate_bullets.items() if not v]
                missing.append(f"rate bullets for: {missing_rates}")
            if not has_activity_heading:
                missing.append("heading_2 '🏃 Activity Breakdown'")
            if not has_toggle_standup:
                missing.append("toggle block for Weekly Standup")
            if not has_toggle_bug:
                missing.append("toggle block for Bug Tracker")
            if not has_toggle_feature:
                missing.append("toggle block for Feature Requests")
            if not has_recommendations_heading:
                missing.append("heading_2 '🎯 Recommendations'")
            if not has_recommendations_paragraph:
                missing.append("recommendations paragraph identifying Feature Requests as lowest")
        
            if missing:
                errors.append(f"[X] Team Performance Dashboard is missing: {', '.join(missing)}")
            else:
                checks_passed.append(f"[C] Team Performance Dashboard is has")
        
            return TaskScore(
                score=1.0 if len(errors) == 0 else 0.0,
                metadata=ScoreMetadata(
                    success_accumulator=list(dict.fromkeys(checks_passed)),
                    error_accumulator=list(dict.fromkeys(errors)),
                )
            )
    
        except Exception as e:
            errors.append(f"[X] Error validating team performance dashboard: {str(e)}")
            return TaskScore(
                score=0.0,
                metadata=ScoreMetadata(
                    success_accumulator=list(dict.fromkeys(checks_passed)),
                    error_accumulator=list(dict.fromkeys(errors)),
                )
            )

    # -----------------------------------------------------------------------------
    # create-team-task-dashboard-v2
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_create_team_task_dashboard(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate that the agent created a Team Task Dashboard with task distribution by team member.
    
    Success criteria:
    1. Team Task Dashboard page exists as sibling to Meeting Notes (same parent/root level)
    2. Contains heading_1 '👥 Team Task Dashboard'
    3. Contains heading_2 '📋 Task Distribution by Team Member'
    4. heading_3 with 👤 emoji for Alice and Bob
    5. Bulleted lists showing tasks with status emojis (✅/⬜)
    6. Blue callout with heading_3 'Summary Statistics' and completion rate text
    
    Expected: Alice (1 task, checked), Bob (1 task, checked) = 2 total, 100% completion
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    try:
        try:
            # Find Meeting Notes page to determine sibling level
            meeting_notes_pages = _get_pages(backend, "Meeting Notes")
        
            if not meeting_notes_pages:
                errors.append("[X] Meeting Notes page not found (needed to verify sibling relationship)")
            else:
                checks_passed.append("[C] Meeting Notes page found (needed to verify sibling relationship)")
        
            meeting_notes_page = meeting_notes_pages[0]
            meeting_notes_parent_id = meeting_notes_page.get("parentId") or meeting_notes_page.get("parent_id")
        
            # Find Team Task Dashboard page
            dashboard_pages = _get_pages(backend, "Team Task Dashboard")
        
            if not dashboard_pages:
                errors.append("[X] Team Task Dashboard page not found")
            else:
                checks_passed.append("[C] Team Task Dashboard page found")
        
            dashboard_page = dashboard_pages[0]
            dashboard_parent_id = dashboard_page.get("parentId") or dashboard_page.get("parent_id")
        
            # Check if Dashboard is sibling of Meeting Notes (same parent)
            if dashboard_parent_id != meeting_notes_parent_id:
                errors.append(f"[X] Team Task Dashboard is not a sibling of Meeting Notes (different parents: {dashboard_parent_id} vs {meeting_notes_parent_id})")
            else:
                checks_passed.append(f"[C] Team Task Dashboard is a sibling of Meeting Notes (different parents: {dashboard_parent_id} vs {meeting_notes_parent_id})")
        
            # Get blocks from Dashboard page
            page_id = dashboard_page.get("_id")
            blocks = _get_blocks(backend, page_id)
            if not blocks:
                errors.append("[X] Team Task Dashboard page has no content blocks")
            else:
                checks_passed.append("[C] Team Task Dashboard page has content blocks")
        
            # Validate required components
            has_main_heading = False
            has_distribution_heading = False
            has_alice_heading = False
            has_bob_heading = False
            has_blue_callout = False
            has_summary_heading = False
            has_completion_rate = False
        
            for block in blocks:
                block_type = block.get("type", "")
                content = block.get("content", "")
                properties = block.get("properties", {})
            
                # Check heading_1
                if block_type == "heading1" and "Team Task Dashboard" in content and "👥" in content:
                    has_main_heading = True
            
                # Check heading_2 Task Distribution
                if block_type == "heading2" and "Task Distribution" in content and "📋" in content:
                    has_distribution_heading = True
            
                # Check heading_3 for Alice with 👤 emoji
                if block_type == "heading3" and "Alice" in content and "👤" in content:
                    has_alice_heading = True
            
                # Check heading_3 for Bob with 👤 emoji
                if block_type == "heading3" and "Bob" in content and "👤" in content:
                    has_bob_heading = True
            
                # Check blue callout
                if block_type == "callout":
                    bg_color = properties.get("backgroundColor", "")
                    if "blue" in bg_color.lower():
                        has_blue_callout = True
                        # Check for nested content (children)
                        children = block.get("children", [])
                        for child in children:
                            child_type = child.get("type", "")
                            child_content = child.get("content", "")
                            if child_type == "heading3" and "Summary Statistics" in child_content:
                                has_summary_heading = True
                            if "100%" in child_content or ("2" in child_content and "total" in child_content.lower()):
                                has_completion_rate = True
                        # Also check callout content itself
                        if "100%" in content or "Total tasks" in content:
                            has_completion_rate = True
        
            # Check all requirements
            missing = []
            if not has_main_heading:
                missing.append("heading_1 '👥 Team Task Dashboard'")
            if not has_distribution_heading:
                missing.append("heading_2 '📋 Task Distribution by Team Member'")
            if not has_alice_heading:
                missing.append("heading_3 '👤 Alice'")
            if not has_bob_heading:
                missing.append("heading_3 '👤 Bob'")
            if not has_blue_callout:
                missing.append("blue callout")
            if not has_summary_heading:
                missing.append("heading_3 'Summary Statistics' inside callout")
            if not has_completion_rate:
                missing.append("completion rate showing 2 total tasks and 100%")
        
            if missing:
                errors.append(f"[X] Team Task Dashboard is missing: {', '.join(missing)}")
            else:
                checks_passed.append(f"[C] Team Task Dashboard is has")
        
            return TaskScore(
                score=1.0 if len(errors) == 0 else 0.0,
                metadata=ScoreMetadata(
                    success_accumulator=list(dict.fromkeys(checks_passed)),
                    error_accumulator=list(dict.fromkeys(errors)),
                )
            )
    
        except Exception as e:
            errors.append(f"[X] Error validating team task dashboard: {str(e)}")
            return TaskScore(
                score=0.0,
                metadata=ScoreMetadata(
                    success_accumulator=list(dict.fromkeys(checks_passed)),
                    error_accumulator=list(dict.fromkeys(errors)),
                )
            )

    # -----------------------------------------------------------------------------
    # reorganize-prd-overview-sections-v2
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_reorganize_prd_overview_sections(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate that the agent reorganized the PRD Overview section into a toggle block.
    
    Success criteria:
    1. Comprehensive Product Requirements Document page exists
    2. Toggle block '📂 Overview Sections (Expandable)' exists after Overview heading_2
    3. All 'Overview - Part X' heading_3 blocks are inside the toggle
    4. Associated paragraph and bulleted list content preserved in toggle
    5. Blue callout with '📌' icon after toggle
    6. Callout contains heading_3 'Quick Stats' and accurate counts
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    try:
        try:
            # Find Comprehensive Product Requirements Document page
            prd_pages = _get_pages(backend, "Comprehensive Product Requirements Document")
        
            if not prd_pages:
                errors.append("[X] Comprehensive Product Requirements Document page not found")
            else:
                checks_passed.append("[C] Comprehensive Product Requirements Document page found")
        
            prd_page = prd_pages[0]
            page_id = prd_page.get("_id")
        
            # Get blocks from PRD page
            blocks = _get_blocks(backend, page_id)
            if not blocks:
                errors.append("[X] PRD page has no content blocks")
            else:
                checks_passed.append("[C] PRD page has content blocks")
        
            # Find key positions and components
            overview_heading_index = -1
            toggle_index = -1
            callout_index = -1
        
            has_overview_heading = False
            has_toggle_block = False
            has_overview_parts_in_toggle = False
            has_blue_callout = False
            has_quick_stats_heading = False
            has_section_count = False
            has_bullet_count = False
        
            overview_part_count = 0
            bullet_count_in_toggle = 0
        
            for i, block in enumerate(blocks):
                block_type = block.get("type", "")
                content = block.get("content", "")
                properties = block.get("properties", {})
            
                # Find Overview heading_2
                if block_type == "heading2" and content == "Overview":
                    has_overview_heading = True
                    overview_heading_index = i
            
                # Find toggle block
                if block_type == "toggle" and "Overview Sections" in content and "📂" in content:
                    has_toggle_block = True
                    toggle_index = i
                
                    # Check toggle children for Overview - Part sections
                    children = block.get("children", [])
                    for child in children:
                        child_content = child.get("content", "")
                        child_type = child.get("type", "")
                    
                        if child_type == "heading3" and "Overview - Part" in child_content:
                            overview_part_count += 1
                            has_overview_parts_in_toggle = True
                    
                        if child_type == "bulletedList":
                            bullet_count_in_toggle += 1
            
                # Find blue callout with 📌 icon
                if block_type == "callout":
                    bg_color = properties.get("backgroundColor", "")
                    icon = properties.get("icon", "")
                    if "blue" in bg_color.lower() and "📌" in icon:
                        has_blue_callout = True
                        callout_index = i
                    
                        # Check callout children
                        children = block.get("children", [])
                        for child in children:
                            child_type = child.get("type", "")
                            child_content = child.get("content", "")
                        
                            if child_type == "heading3" and "Quick Stats" in child_content:
                                has_quick_stats_heading = True
                        
                            if child_type == "bulletedList":
                                if "Total Overview Sections" in child_content:
                                    has_section_count = True
                                if "Total Key Points" in child_content:
                                    has_bullet_count = True
        
            # Verify positioning: toggle should be after overview heading
            if toggle_index != -1 and overview_heading_index != -1:
                if toggle_index <= overview_heading_index:
                    errors.append("[X] Toggle block must appear AFTER Overview heading_2")
                else:
                    checks_passed.append("[C] Toggle block must appear AFTER Overview heading_2")
        
            # Verify callout is after toggle
            if callout_index != -1 and toggle_index != -1:
                if callout_index <= toggle_index:
                    errors.append("[X] Blue callout must appear AFTER toggle block")
                else:
                    checks_passed.append("[C] Blue callout must appear AFTER toggle block")
        
            # Check all requirements
            missing = []
            if not has_overview_heading:
                missing.append("Overview heading_2")
            if not has_toggle_block:
                missing.append("toggle block '📂 Overview Sections (Expandable)'")
            if not has_overview_parts_in_toggle:
                missing.append("'Overview - Part' sections inside toggle")
            if not has_blue_callout:
                missing.append("blue callout with 📌 icon")
            if not has_quick_stats_heading:
                missing.append("heading_3 'Quick Stats' inside callout")
            if not has_section_count:
                missing.append("'Total Overview Sections' count in callout")
            if not has_bullet_count:
                missing.append("'Total Key Points' count in callout")
        
            if missing:
                errors.append(f"[X] PRD Overview reorganization is missing: {', '.join(missing)}")
            else:
                checks_passed.append(f"[C] PRD Overview reorganization is has")
        
            return TaskScore(
                score=1.0 if len(errors) == 0 else 0.0,
                metadata=ScoreMetadata(
                    success_accumulator=list(dict.fromkeys(checks_passed)),
                    error_accumulator=list(dict.fromkeys(errors)),
                )
            )
    
        except Exception as e:
            errors.append(f"[X] Error validating PRD overview reorganization: {str(e)}")
            return TaskScore(
                score=0.0,
                metadata=ScoreMetadata(
                    success_accumulator=list(dict.fromkeys(checks_passed)),
                    error_accumulator=list(dict.fromkeys(errors)),
                )
            )

    # -----------------------------------------------------------------------------
    # reorganize-feature-requests-by-status-v2
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_reorganize_feature_requests_by_status(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate that the agent reorganized Feature Requests page by implementation status.
    
    Success criteria:
    1. Feature Requests page exists
    2. heading_2 '🔥 Implementation Status' exists between intro and 'High Priority'
    3. Three subsections: '✅ Completed Features', '🚧 In Progress', '📋 Backlog'
    4. Checked todos moved to Completed Features
    5. Unchecked todos with 'support'/'integration' moved to In Progress
    6. Other unchecked todos moved to Backlog
    7. Green callout at end with accurate completion rate
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    try:
        try:
            # Find Feature Requests page
            feature_pages = _get_pages(backend, "Feature Requests")
        
            if not feature_pages:
                errors.append("[X] Feature Requests page not found")
            else:
                checks_passed.append("[C] Feature Requests page found")
        
            feature_page = feature_pages[0]
            page_id = feature_page.get("_id")
        
            # Get blocks from Feature Requests page
            blocks = _get_blocks(backend, page_id)
            if not blocks:
                errors.append("[X] Feature Requests page has no content blocks")
            else:
                checks_passed.append("[C] Feature Requests page has content blocks")
        
            # Find key positions and components
            implementation_status_index = -1
            high_priority_index = -1
            completed_index = -1
            in_progress_index = -1
            backlog_index = -1
            green_callout_index = -1
        
            has_implementation_heading = False
            has_completed_heading = False
            has_in_progress_heading = False
            has_backlog_heading = False
            has_green_callout = False
            has_rate_text = False
        
            # Track todos in each section
            todos_in_completed = 0
            todos_in_progress = 0
            todos_in_backlog = 0
        
            current_section = None
        
            for i, block in enumerate(blocks):
                block_type = block.get("type", "")
                content = block.get("content", "")
                properties = block.get("properties", {})
            
                # Find Implementation Status heading_2
                if block_type == "heading2" and "Implementation Status" in content and "🔥" in content:
                    has_implementation_heading = True
                    implementation_status_index = i
            
                # Find High Priority heading_2
                if block_type == "heading2" and "High Priority" in content:
                    high_priority_index = i
            
                # Find Completed Features heading_3
                if block_type == "heading3" and "Completed Features" in content and "✅" in content:
                    has_completed_heading = True
                    completed_index = i
                    current_section = "completed"
            
                # Find In Progress heading_3
                if block_type == "heading3" and "In Progress" in content and "🚧" in content:
                    has_in_progress_heading = True
                    in_progress_index = i
                    current_section = "in_progress"
            
                # Find Backlog heading_3
                if block_type == "heading3" and "Backlog" in content and "📋" in content:
                    has_backlog_heading = True
                    backlog_index = i
                    current_section = "backlog"
            
                # Count todos in sections
                if block_type == "todo":
                    if current_section == "completed":
                        todos_in_completed += 1
                    elif current_section == "in_progress":
                        todos_in_progress += 1
                    elif current_section == "backlog":
                        todos_in_backlog += 1
            
                # Reset section on other heading_2
                if block_type == "heading2" and current_section:
                    if "Implementation Status" not in content:
                        current_section = None
            
                # Find green callout at end
                if block_type == "callout":
                    bg_color = properties.get("backgroundColor", "")
                    if "green" in bg_color.lower():
                        has_green_callout = True
                        green_callout_index = i
                        if "implementation rate" in content.lower() or ("%" in content and "completed" in content.lower()):
                            has_rate_text = True
        
            # Verify positioning: Implementation Status should be before High Priority
            if implementation_status_index != -1 and high_priority_index != -1:
                if implementation_status_index >= high_priority_index:
                    errors.append("[X] Implementation Status heading must appear BEFORE High Priority section")
                else:
                    checks_passed.append("[C] Implementation Status heading must appear BEFORE High Priority section")
        
            # Verify green callout is at/near end
            if green_callout_index != -1:
                if green_callout_index < len(blocks) - 5:  # Allow some flexibility
                    pass  # Acceptable position
        
            # Check all requirements
            missing = []
            if not has_implementation_heading:
                missing.append("heading_2 '🔥 Implementation Status'")
            if not has_completed_heading:
                missing.append("heading_3 '✅ Completed Features'")
            if not has_in_progress_heading:
                missing.append("heading_3 '🚧 In Progress'")
            if not has_backlog_heading:
                missing.append("heading_3 '📋 Backlog'")
            if not has_green_callout:
                missing.append("green callout")
            if not has_rate_text:
                missing.append("implementation rate text in callout")
        
            if missing:
                errors.append(f"[X] Feature Requests reorganization is missing: {', '.join(missing)}")
            else:
                checks_passed.append(f"[C] Feature Requests reorganization is has")
        
            total_todos = todos_in_completed + todos_in_progress + todos_in_backlog
            if total_todos == 0:
                errors.append("[X] Sections exist but no todos found in them")
            else:
                checks_passed.append(f"[C] Found {total_todos} todos distributed across sections")

            return TaskScore(
                score=1.0 if len(errors) == 0 else 0.0,
                metadata=ScoreMetadata(
                    success_accumulator=list(dict.fromkeys(checks_passed)),
                    error_accumulator=list(dict.fromkeys(errors)),
                )
            )
    
        except Exception as e:
            errors.append(f"[X] Error validating feature requests reorganization: {str(e)}")
            return TaskScore(
                score=0.0,
                metadata=ScoreMetadata(
                    success_accumulator=list(dict.fromkeys(checks_passed)),
                    error_accumulator=list(dict.fromkeys(errors)),
                )
            )

    # -----------------------------------------------------------------------------
    # transform-standup-template-dynamic-v2
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_transform_standup_template_dynamic(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate that the agent transformed Weekly Standup Template into a dynamic template.
    
    Success criteria:
    1. Blue callout with 📅 icon after intro, before 'What I did this week'
    2. Toggle blocks with tips after each heading_2 section
    3. heading_2 '📈 Weekly Metrics' at the end with three specific todos
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    try:
        try:
            # Find Weekly Standup Template page
            template_pages = _get_pages(backend, "Weekly Standup Template")
        
            if not template_pages:
                errors.append("[X] Weekly Standup Template page not found")
            else:
                checks_passed.append("[C] Weekly Standup Template page found")
        
            template_page = template_pages[0]
            page_id = template_page.get("_id")
        
            # Get blocks from template page
            blocks = _get_blocks(backend, page_id)
            if not blocks:
                errors.append("[X] Weekly Standup Template page has no content blocks")
            else:
                checks_passed.append("[C] Weekly Standup Template page has content blocks")
        
            # Find key positions and components
            intro_paragraph_index = -1
            what_i_did_index = -1
            date_callout_index = -1
            metrics_heading_index = -1
        
            has_date_callout = False
            has_toggle_what_i_did = False
            has_toggle_next_week = False
            has_toggle_blockers = False
            has_metrics_heading = False
            has_time_tracking_todo = False
            has_productivity_todo = False
            has_goal_alignment_todo = False
        
            for i, block in enumerate(blocks):
                block_type = block.get("type", "")
                content = block.get("content", "")
                properties = block.get("properties", {})
            
                # Find intro paragraph
                if block_type == "paragraph" and "Use this template" in content:
                    intro_paragraph_index = i
            
                # Find 'What I did this week' heading
                if block_type == "heading2" and "What I did this week" in content:
                    what_i_did_index = i
            
                # Find blue date callout with 📅 icon
                if block_type == "callout":
                    bg_color = properties.get("backgroundColor", "")
                    icon = properties.get("icon", "")
                    if "blue" in bg_color.lower() and "📅" in icon and "Week of" in content:
                        has_date_callout = True
                        date_callout_index = i
            
                # Find toggle blocks with tips
                if block_type == "toggle" and "Tips for this section" in content:
                    # Check children for specific guidance text
                    children = block.get("children", [])
                    for child in children:
                        child_content = child.get("content", "")
                        if "completed deliverables" in child_content.lower() or "business impact" in child_content.lower():
                            has_toggle_what_i_did = True
                        if "timelines" in child_content.lower() or "dependencies" in child_content.lower():
                            has_toggle_next_week = True
                        if "solutions" in child_content.lower() or "help needed" in child_content.lower():
                            has_toggle_blockers = True
            
                # Find Weekly Metrics heading
                if block_type == "heading2" and "Weekly Metrics" in content and "📈" in content:
                    has_metrics_heading = True
                    metrics_heading_index = i
            
                # Find the three specific todos
                if block_type == "todo":
                    if "time tracking" in content.lower() or "⏱️" in content:
                        has_time_tracking_todo = True
                    if "productivity score" in content.lower() or "📊" in content:
                        has_productivity_todo = True
                    if "goal alignment" in content.lower() or "🎯" in content:
                        has_goal_alignment_todo = True
        
            # Verify date callout positioning (after intro, before what I did)
            if date_callout_index != -1 and intro_paragraph_index != -1 and what_i_did_index != -1:
                if not (intro_paragraph_index < date_callout_index < what_i_did_index):
                    errors.append(f"[X] Date callout must be after intro (index {intro_paragraph_index}) and before 'What I did this week' (index {what_i_did_index}), found at {date_callout_index}")
                else:
                    checks_passed.append(f"[C] Date callout must be after intro (index {intro_paragraph_index}) and before 'What I did this week' (index {what_i_did_index}), found at {date_callout_index}")
        
            # Verify metrics section is at the end
            if metrics_heading_index != -1:
                if metrics_heading_index < len(blocks) - 10:  # Allow some flexibility for todos after
                    pass  # Acceptable
        
            # Check all requirements
            missing = []
            if not has_date_callout:
                missing.append("blue callout with 📅 icon containing 'Week of'")
            if not has_toggle_what_i_did:
                missing.append("toggle with 'What I did' tips (completed deliverables/business impact)")
            if not has_toggle_next_week:
                missing.append("toggle with 'Next week' tips (timelines/dependencies)")
            if not has_toggle_blockers:
                missing.append("toggle with 'Blockers' tips (solutions/help needed)")
            if not has_metrics_heading:
                missing.append("heading_2 '📈 Weekly Metrics'")
            if not has_time_tracking_todo:
                missing.append("todo '⏱️ Update time tracking'")
            if not has_productivity_todo:
                missing.append("todo '📊 Log productivity score'")
            if not has_goal_alignment_todo:
                missing.append("todo '🎯 Review goal alignment'")
        
            if missing:
                errors.append(f"[X] Dynamic standup template is missing: {', '.join(missing)}")
            else:
                checks_passed.append(f"[C] Dynamic standup template is has")
        
            return TaskScore(
                score=1.0 if len(errors) == 0 else 0.0,
                metadata=ScoreMetadata(
                    success_accumulator=list(dict.fromkeys(checks_passed)),
                    error_accumulator=list(dict.fromkeys(errors)),
                )
            )
    
        except Exception as e:
            errors.append(f"[X] Error validating dynamic standup template: {str(e)}")
            return TaskScore(
                score=0.0,
                metadata=ScoreMetadata(
                    success_accumulator=list(dict.fromkeys(checks_passed)),
                    error_accumulator=list(dict.fromkeys(errors)),
                )
            )

    # -----------------------------------------------------------------------------
    # analyze-prd-content-metrics-v2
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_analyze_prd_content_metrics(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate that the agent analyzed PRD content and added metrics.
    
    Success criteria:
    1. Blue callout with 📊 icon after 'User Stories' heading, before first subsection
    2. Callout shows correct counts of heading_2 and heading_3 blocks
    3. heading_2 '🔍 Document Metrics' at the very end
    4. Numbered list with correct calculations (average rounded to 1 decimal)
    5. Quote block with exact specified text
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    try:
        try:
            # Find Comprehensive Product Requirements Document page
            prd_pages = _get_pages(backend, "Comprehensive Product Requirements Document")
        
            if not prd_pages:
                errors.append("[X] Comprehensive Product Requirements Document page not found")
            else:
                checks_passed.append("[C] Comprehensive Product Requirements Document page found")
        
            prd_page = prd_pages[0]
            page_id = prd_page.get("_id")
        
            # Get blocks from PRD page
            blocks = _get_blocks(backend, page_id)
            if not blocks:
                errors.append("[X] PRD page has no content blocks")
            else:
                checks_passed.append("[C] PRD page has content blocks")
        
            # Count heading_2 and heading_3 blocks
            heading2_count = 0
            heading3_count = 0
        
            for block in blocks:
                block_type = block.get("type", "")
                if block_type == "heading2":
                    heading2_count += 1
                elif block_type == "heading3":
                    heading3_count += 1
        
            # Find key positions and components
            user_stories_heading_index = -1
            user_stories_part1_index = -1
            analysis_callout_index = -1
            metrics_heading_index = -1
        
            has_analysis_callout = False
            has_correct_counts_in_callout = False
            has_metrics_heading = False
            has_numbered_list = False
            has_quote_block = False
        
            for i, block in enumerate(blocks):
                block_type = block.get("type", "")
                content = block.get("content", "")
                properties = block.get("properties", {})
            
                # Find User Stories heading_2
                if block_type == "heading2" and content == "User Stories":
                    user_stories_heading_index = i
            
                # Find User Stories - Part 1 heading_3
                if block_type == "heading3" and "User Stories - Part 1" in content:
                    user_stories_part1_index = i
            
                # Find blue analysis callout with 📊 icon
                if block_type == "callout":
                    bg_color = properties.get("backgroundColor", "")
                    icon = properties.get("icon", "")
                    if "blue" in bg_color.lower() and "📊" in icon:
                        if "Section Analysis" in content or "sections" in content.lower():
                            has_analysis_callout = True
                            analysis_callout_index = i
                            # Check if counts are mentioned
                            if "major sections" in content.lower() and "subsections" in content.lower():
                                has_correct_counts_in_callout = True
            
                # Find Document Metrics heading
                if block_type == "heading2" and "Document Metrics" in content and "🔍" in content:
                    has_metrics_heading = True
                    metrics_heading_index = i
            
                # Find numbered list with metrics
                if block_type == "numberedList":
                    if "Total sections" in content or "Total subsections" in content or "Average" in content:
                        has_numbered_list = True
            
                # Find quote block
                if block_type == "quote":
                    if "well-structured PRD" in content and "foundation" in content:
                        has_quote_block = True
        
            # Verify callout positioning (after User Stories, before Part 1)
            if analysis_callout_index != -1 and user_stories_heading_index != -1 and user_stories_part1_index != -1:
                if not (user_stories_heading_index < analysis_callout_index < user_stories_part1_index):
                    errors.append(f"[X] Analysis callout must be after 'User Stories' heading and before 'User Stories - Part 1'")
                else:
                    checks_passed.append(f"[C] Analysis callout must be after 'User Stories' heading and before 'User Stories - Part 1'")
        
            # Verify metrics section is near the end
            if metrics_heading_index != -1:
                if metrics_heading_index < len(blocks) - 6:  # Should be near end
                    pass  # Some flexibility
        
            # Check all requirements
            missing = []
            if not has_analysis_callout:
                missing.append("blue callout with 📊 icon for section analysis")
            if not has_correct_counts_in_callout:
                missing.append("callout with major sections and subsections counts")
            if not has_metrics_heading:
                missing.append("heading_2 '🔍 Document Metrics'")
            if not has_numbered_list:
                missing.append("numbered list with section counts and average")
            if not has_quote_block:
                missing.append("quote block about well-structured PRD")
        
            if missing:
                errors.append(f"[X] PRD content analysis is missing: {', '.join(missing)}")
            else:
                checks_passed.append(f"[C] PRD content analysis is has")
        
            return TaskScore(
                score=1.0 if len(errors) == 0 else 0.0,
                metadata=ScoreMetadata(
                    success_accumulator=list(dict.fromkeys(checks_passed)),
                    error_accumulator=list(dict.fromkeys(errors)),
                )
            )
    
        except Exception as e:
            errors.append(f"[X] Error validating PRD content analysis: {str(e)}")
            return TaskScore(
                score=0.0,
                metadata=ScoreMetadata(
                    success_accumulator=list(dict.fromkeys(checks_passed)),
                    error_accumulator=list(dict.fromkeys(errors)),
                )
            )

    # -----------------------------------------------------------------------------
    # add-onboarding-tracking-system-v2
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_add_onboarding_tracking_system(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate that the agent added an onboarding tracking system to the Onboarding Guide page.
    
    Success criteria:
    1. heading_3 '✅ Onboarding Checklist' exists after First Week Goals section
    2. Callout with brown_background and warning icon with bold text about completing items
    3. Five specific unchecked todo blocks
    4. Divider after todos
    5. heading_3 '📊 Progress Tracker'
    6. Code block with language 'markdown' containing the day progress items
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    try:
        try:
            # Find Onboarding Guide page
            onboarding_pages = _get_pages(backend, "Onboarding Guide")
        
            if not onboarding_pages:
                errors.append("[X] Onboarding Guide page not found")
            else:
                checks_passed.append("[C] Onboarding Guide page found")
        
            onboarding_page = onboarding_pages[0]
            page_id = onboarding_page.get("_id")
        
            # Get blocks from the page
            blocks = _get_blocks(backend, page_id)
            if not blocks:
                errors.append("[X] Onboarding Guide page has no content blocks")
            else:
                checks_passed.append("[C] Onboarding Guide page has content blocks")
        
            # Find key positions and components
            first_week_goals_index = -1
            checklist_heading_index = -1
            progress_tracker_index = -1
        
            has_checklist_heading = False
            has_warning_callout = False
            has_all_todos = False
            has_divider_after_todos = False
            has_progress_tracker = False
            has_code_block = False
        
            expected_todos = [
                "📧 Set up email signature with company template",
                "🔐 Enable two-factor authentication on all accounts",
                "📸 Upload professional photo to company directory",
                "📚 Complete compliance training modules",
                "🤝 Schedule coffee chats with 3 team members"
            ]
            found_todos = []
        
            for i, block in enumerate(blocks):
                block_type = block.get("type", "")
                content = block.get("content", "")
                properties = block.get("properties", {})
            
                # Find First Week Goals heading
                if block_type == "heading2" and "First Week Goals" in content:
                    first_week_goals_index = i
            
                # Find Onboarding Checklist heading_3
                if block_type == "heading3" and "Onboarding Checklist" in content and "✅" in content:
                    has_checklist_heading = True
                    checklist_heading_index = i
            
                # Find warning callout with brown background
                if block_type == "callout":
                    bg_color = properties.get("backgroundColor", "")
                    icon = properties.get("icon", "")
                    if "brown" in bg_color.lower():
                        if "Complete all items" in content and "first week" in content.lower():
                            has_warning_callout = True
            
                # Find todos
                if block_type == "todo":
                    checked = properties.get("checked", False)
                    if not checked:
                        for expected_todo in expected_todos:
                            if expected_todo in content and expected_todo not in found_todos:
                                found_todos.append(expected_todo)
            
                # Find divider
                if block_type == "divider":
                    # Check if it's after todos and before progress tracker
                    if checklist_heading_index != -1 and len(found_todos) >= 5:
                        has_divider_after_todos = True
            
                # Find Progress Tracker heading_3
                if block_type == "heading3" and "Progress Tracker" in content and "📊" in content:
                    has_progress_tracker = True
                    progress_tracker_index = i
            
                # Find code block with markdown
                if block_type == "code":
                    language = properties.get("language", "")
                    if language.lower() == "markdown" or "markdown" in language.lower():
                        if "Day 1" in content and "Day 3" in content and "Day 5" in content:
                            has_code_block = True
        
            # Check all todos found
            has_all_todos = len(found_todos) == len(expected_todos)
        
            # Verify ordering: First Week Goals < Checklist Heading < Progress Tracker
            if first_week_goals_index != -1 and checklist_heading_index != -1:
                if checklist_heading_index <= first_week_goals_index:
                    errors.append("[X] Onboarding Checklist must appear AFTER First Week Goals section")
                else:
                    checks_passed.append("[C] Onboarding Checklist must appear AFTER First Week Goals section")
        
            if checklist_heading_index != -1 and progress_tracker_index != -1:
                if progress_tracker_index <= checklist_heading_index:
                    errors.append("[X] Progress Tracker must appear AFTER Onboarding Checklist")
                else:
                    checks_passed.append("[C] Progress Tracker must appear AFTER Onboarding Checklist")
        
            # Check all requirements
            missing = []
            if not has_checklist_heading:
                missing.append("heading_3 '✅ Onboarding Checklist'")
            if not has_warning_callout:
                missing.append("callout with brown background and warning about completing items in first week")
            if not has_all_todos:
                missing.append(f"all 5 unchecked todos (found {len(found_todos)}/5)")
            if not has_divider_after_todos:
                missing.append("divider after todos")
            if not has_progress_tracker:
                missing.append("heading_3 '📊 Progress Tracker'")
            if not has_code_block:
                missing.append("code block with markdown language containing day progress items")
        
            if missing:
                errors.append(f"[X] Onboarding tracking system is missing: {', '.join(missing)}")
            else:
                checks_passed.append(f"[C] Onboarding tracking system is has")
        
            return TaskScore(
                score=1.0 if len(errors) == 0 else 0.0,
                metadata=ScoreMetadata(
                    success_accumulator=list(dict.fromkeys(checks_passed)),
                    error_accumulator=list(dict.fromkeys(errors)),
                )
            )
    
        except Exception as e:
            errors.append(f"[X] Error validating onboarding tracking system: {str(e)}")
            return TaskScore(
                score=0.0,
                metadata=ScoreMetadata(
                    success_accumulator=list(dict.fromkeys(checks_passed)),
                    error_accumulator=list(dict.fromkeys(errors)),
                )
            )

    # -----------------------------------------------------------------------------
    # add-bug-resolution-statistics-v2
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_add_bug_resolution_statistics(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate that the agent added bug resolution statistics to the Bug Tracker page.
    
    Success criteria:
    1. Statistics section positioned between description and 'Critical Bugs' heading
    2. heading_2 '📊 Bug Resolution Statistics' exists
    3. Callout with conditional background (green if >50% resolved, red if ≤50%)
    4. heading_3 'Current Sprint Metrics' inside or after callout
    5. Numbered list with accurate statistics
    6. Bold paragraph with 'Last Updated:' text
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    try:
        try:
            # Find Bug Tracker page
            bug_tracker_pages = _get_pages(backend, "Bug Tracker")
        
            if not bug_tracker_pages:
                errors.append("[X] Bug Tracker page not found")
            else:
                checks_passed.append("[C] Bug Tracker page found")
        
            bug_tracker_page = bug_tracker_pages[0]
            page_id = bug_tracker_page.get("_id")
        
            # Get blocks from the page
            blocks = _get_blocks(backend, page_id)
            if not blocks:
                errors.append("[X] Bug Tracker page has no content blocks")
            else:
                checks_passed.append("[C] Bug Tracker page has content blocks")
        
            # Count todos and calculate statistics
            total_todos = 0
            resolved_todos = 0
            critical_section_started = False
            critical_unchecked = 0
        
            for block in blocks:
                block_type = block.get("type", "")
                content = block.get("content", "")
                properties = block.get("properties", {})
            
                # Track Critical Bugs section
                if block_type == "heading2" and "Critical Bugs" in content:
                    critical_section_started = True
                elif block_type == "heading2" and critical_section_started:
                    critical_section_started = False
            
                # Count todos
                if block_type == "todo":
                    total_todos += 1
                    checked = properties.get("checked", False)
                    if checked:
                        resolved_todos += 1
                    elif critical_section_started:
                        critical_unchecked += 1
        
            open_todos = total_todos - resolved_todos
            completion_rate = (resolved_todos / total_todos * 100) if total_todos > 0 else 0
        
            # Find key positions and components
            title_index = -1
            description_index = -1
            critical_bugs_index = -1
            statistics_heading_index = -1
        
            has_statistics_heading = False
            has_callout_with_correct_color = False
            has_metrics_heading = False
            has_numbered_list_stats = False
            has_last_updated = False
        
            for i, block in enumerate(blocks):
                block_type = block.get("type", "")
                content = block.get("content", "")
                properties = block.get("properties", {})
            
                # Find title (heading1)
                if block_type == "heading1":
                    title_index = i
            
                # Find description paragraph (usually right after title)
                if block_type == "paragraph" and title_index != -1 and description_index == -1:
                    description_index = i
            
                # Find Critical Bugs heading
                if block_type == "heading2" and "Critical Bugs" in content:
                    critical_bugs_index = i
            
                # Find Bug Resolution Statistics heading
                if block_type == "heading2" and "Bug Resolution Statistics" in content and "📊" in content:
                    has_statistics_heading = True
                    statistics_heading_index = i
            
                # Find callout with conditional color
                if block_type == "callout":
                    bg_color = properties.get("backgroundColor", "").lower()
                    if completion_rate > 50:
                        if "green" in bg_color:
                            has_callout_with_correct_color = True
                    else:
                        if "red" in bg_color:
                            has_callout_with_correct_color = True
            
                # Find Current Sprint Metrics heading_3
                if block_type == "heading3" and "Current Sprint Metrics" in content:
                    has_metrics_heading = True
            
                # Find numbered list with statistics
                if block_type == "numberedList":
                    if "Total Bugs" in content or "Resolved Bugs" in content or "Open Bugs" in content or "Critical Bugs" in content:
                        has_numbered_list_stats = True
            
                # Find Last Updated paragraph
                if block_type == "paragraph":
                    if "Last Updated" in content:
                        has_last_updated = True
        
            # Verify positioning: statistics section must be between description and Critical Bugs
            if statistics_heading_index != -1 and description_index != -1 and critical_bugs_index != -1:
                if not (description_index < statistics_heading_index < critical_bugs_index):
                    errors.append(f"[X] Statistics section must be positioned between description (order {description_index}) and Critical Bugs heading (order {critical_bugs_index})")
                else:
                    checks_passed.append(f"[C] Statistics section must be positioned between description (order {description_index}) and Critical Bugs heading (order {critical_bugs_index})")
        
            # Check all requirements
            missing = []
            if not has_statistics_heading:
                missing.append("heading_2 '📊 Bug Resolution Statistics'")
            if not has_callout_with_correct_color:
                expected_color = "green" if completion_rate > 50 else "red"
                missing.append(f"callout with {expected_color} background (completion rate: {completion_rate:.1f}%)")
            if not has_metrics_heading:
                missing.append("heading_3 'Current Sprint Metrics'")
            if not has_numbered_list_stats:
                missing.append("numbered list with statistics")
            if not has_last_updated:
                missing.append("paragraph with 'Last Updated:' text")
        
            if missing:
                errors.append(f"[X] Bug resolution statistics is missing: {', '.join(missing)}")
            else:
                checks_passed.append(f"[C] Bug resolution statistics is has")
        
            return TaskScore(
                score=1.0 if len(errors) == 0 else 0.0,
                metadata=ScoreMetadata(
                    success_accumulator=list(dict.fromkeys(checks_passed)),
                    error_accumulator=list(dict.fromkeys(errors)),
                )
            )
    
        except Exception as e:
            errors.append(f"[X] Error validating bug resolution statistics: {str(e)}")
            return TaskScore(
                score=0.0,
                metadata=ScoreMetadata(
                    success_accumulator=list(dict.fromkeys(checks_passed)),
                    error_accumulator=list(dict.fromkeys(errors)),
                )
            )

    # -----------------------------------------------------------------------------
    # add-sprint-velocity-metrics-v2
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_add_sprint_velocity_metrics(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate that the agent added sprint velocity metrics to the Sprint Planning - Jan 15 page.
    
    Success criteria:
    1. heading_3 '🔄 Sprint Velocity Metrics' appears after the last todo block
    2. Code block with 'javascript' language and correct velocity calculation
    3. Paragraph with italic formatting showing velocity percentage
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    try:
        try:
            # Find Sprint Planning - Jan 15 page
            sprint_pages = _get_pages(backend, "Sprint Planning - Jan 15")
        
            if not sprint_pages:
                errors.append("[X] Sprint Planning - Jan 15 page not found")
            else:
                checks_passed.append("[C] Sprint Planning - Jan 15 page found")
        
            sprint_page = sprint_pages[0]
            page_id = sprint_page.get("_id")
        
            # Get blocks from the page
            blocks = _get_blocks(backend, page_id)
            if not blocks:
                errors.append("[X] Sprint Planning - Jan 15 page has no content blocks")
            else:
                checks_passed.append("[C] Sprint Planning - Jan 15 page has content blocks")
        
            # Count todos
            total_todos = 0
            completed_todos = 0
            last_todo_index = -1
        
            for i, block in enumerate(blocks):
                block_type = block.get("type", "")
                properties = block.get("properties", {})
            
                if block_type == "todo":
                    total_todos += 1
                    last_todo_index = i
                    if properties.get("checked", False):
                        completed_todos += 1
        
            if total_todos == 0:
                errors.append("[X] No todo blocks found on the page")
            else:
                checks_passed.append("[C] todo blocks found on the page")
        
            # Calculate expected velocity
            velocity = (completed_todos / total_todos * 100) if total_todos > 0 else 0
            velocity_str = f"{velocity:.1f}"
        
            # Find required elements
            velocity_heading_index = -1
            has_velocity_heading = False
            has_code_block = False
            has_velocity_paragraph = False
        
            for i, block in enumerate(blocks):
                block_type = block.get("type", "")
                content = block.get("content", "")
                properties = block.get("properties", {})
            
                # Find Sprint Velocity Metrics heading_3
                if block_type == "heading3" and "Sprint Velocity Metrics" in content and "🔄" in content:
                    has_velocity_heading = True
                    velocity_heading_index = i
            
                # Find code block with javascript
                if block_type == "code":
                    language = properties.get("language", "").lower()
                    if "javascript" in language or language == "js":
                        # Check if content has the velocity calculation
                        if "completedTasks" in content and "totalTasks" in content and "velocityScore" in content:
                            has_code_block = True
            
                # Find paragraph with velocity info
                if block_type == "paragraph":
                    if "sprint velocity" in content.lower() and "%" in content:
                        has_velocity_paragraph = True
        
            # Verify positioning: velocity heading must be after last todo
            if velocity_heading_index != -1 and last_todo_index != -1:
                if velocity_heading_index <= last_todo_index:
                    errors.append(f"[X] Sprint Velocity Metrics heading must appear AFTER the last todo block (todo at index {last_todo_index}, heading at {velocity_heading_index})")
                else:
                    checks_passed.append(f"[C] Sprint Velocity Metrics heading must appear AFTER the last todo block (todo at index {last_todo_index}, heading at {velocity_heading_index})")
        
            # Check all requirements
            missing = []
            if not has_velocity_heading:
                missing.append("heading_3 '🔄 Sprint Velocity Metrics'")
            if not has_code_block:
                missing.append("code block with javascript language containing velocity calculation")
            if not has_velocity_paragraph:
                missing.append("paragraph with sprint velocity percentage")
        
            if missing:
                errors.append(f"[X] Sprint velocity metrics is missing: {', '.join(missing)}")
            else:
                checks_passed.append(f"[C] Sprint velocity metrics is has")
        
            return TaskScore(
                score=1.0 if len(errors) == 0 else 0.0,
                metadata=ScoreMetadata(
                    success_accumulator=list(dict.fromkeys(checks_passed)),
                    error_accumulator=list(dict.fromkeys(errors)),
                )
            )
    
        except Exception as e:
            errors.append(f"[X] Error validating sprint velocity metrics: {str(e)}")
            return TaskScore(
                score=0.0,
                metadata=ScoreMetadata(
                    success_accumulator=list(dict.fromkeys(checks_passed)),
                    error_accumulator=list(dict.fromkeys(errors)),
                )
            )

    # -----------------------------------------------------------------------------
    # add-hot-fixes-section-v2
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_add_hot_fixes_section(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate that the agent added a Hot Fixes section to the Bug Tracker page.
    
    Success criteria:
    1. heading_2 '🔥 Hot Fixes (Last 24 Hours)' between Medium and Low Priority sections
    2. Copied unchecked todos containing 'sync', 'real-time', or 'timeout' keywords
    3. Divider after the copied todos
    4. Red callout with ⚡ icon showing correct count of critical bugs
    5. Bold paragraph with timestamp
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    try:
        try:
            # Find Bug Tracker page
            bug_tracker_pages = _get_pages(backend, "Bug Tracker")
        
            if not bug_tracker_pages:
                errors.append("[X] Bug Tracker page not found")
            else:
                checks_passed.append("[C] Bug Tracker page found")
        
            bug_tracker_page = bug_tracker_pages[0]
            page_id = bug_tracker_page.get("_id")
        
            # Get blocks from the page
            blocks = _get_blocks(backend, page_id)
            if not blocks:
                errors.append("[X] Bug Tracker page has no content blocks")
            else:
                checks_passed.append("[C] Bug Tracker page has content blocks")
        
            # Find key positions
            medium_priority_index = -1
            hot_fixes_index = -1
            low_priority_index = -1
        
            has_hot_fixes_heading = False
            has_divider_in_hot_fixes = False
            has_red_callout = False
            has_timestamp_paragraph = False
            hot_fixes_todos = []
        
            # Keywords to match
            keywords = ['sync', 'real-time', 'timeout']
        
            for i, block in enumerate(blocks):
                block_type = block.get("type", "")
                content = block.get("content", "")
                properties = block.get("properties", {})
            
                # Find Medium Priority heading
                if block_type == "heading2" and "Medium Priority" in content:
                    medium_priority_index = i
            
                # Find Hot Fixes heading
                if block_type == "heading2" and "Hot Fixes" in content and "🔥" in content:
                    has_hot_fixes_heading = True
                    hot_fixes_index = i
            
                # Find Low Priority heading
                if block_type == "heading2" and "Low Priority" in content:
                    low_priority_index = i
            
                # Find todos in Hot Fixes section (between hot fixes heading and next heading or divider)
                if hot_fixes_index != -1 and (low_priority_index == -1 or i < low_priority_index):
                    if block_type == "todo":
                        # Check if this is a hot fix todo (contains keywords)
                        content_lower = content.lower()
                        if any(kw in content_lower for kw in keywords):
                            hot_fixes_todos.append({
                                "content": content,
                                "checked": properties.get("checked", False)
                            })
                
                    if block_type == "divider":
                        has_divider_in_hot_fixes = True
            
                # Find red callout with ⚡ icon
                if block_type == "callout":
                    bg_color = properties.get("backgroundColor", "").lower()
                    icon = properties.get("icon", "")
                    if "red" in bg_color and "⚡" in icon:
                        if "Critical issues" in content and "bugs" in content:
                            has_red_callout = True
            
                # Find timestamp paragraph
                if block_type == "paragraph":
                    if "Last triaged" in content or "triaged:" in content.lower():
                        # Check for bold
                        if properties.get("bold", False):
                            has_timestamp_paragraph = True
        
            # Verify positioning
            if hot_fixes_index != -1:
                if medium_priority_index != -1 and hot_fixes_index <= medium_priority_index:
                    errors.append("[X] Hot Fixes section must appear AFTER Medium Priority section")
                else:
                    checks_passed.append("[C] Hot Fixes section must appear AFTER Medium Priority section")
                if low_priority_index != -1 and hot_fixes_index >= low_priority_index:
                    errors.append("[X] Hot Fixes section must appear BEFORE Low Priority section")
                else:
                    checks_passed.append("[C] Hot Fixes section must appear BEFORE Low Priority section")
        
            # Count unchecked hot fix todos
            unchecked_hot_fixes = [t for t in hot_fixes_todos if not t.get("checked", False)]
        
            # Check all requirements
            missing = []
            if not has_hot_fixes_heading:
                missing.append("heading_2 '🔥 Hot Fixes (Last 24 Hours)'")
            if len(unchecked_hot_fixes) < 2:
                missing.append(f"at least 2 unchecked todos with keywords (found {len(unchecked_hot_fixes)})")
            if not has_divider_in_hot_fixes:
                missing.append("divider after hot fix todos")
            if not has_red_callout:
                missing.append("red callout with ⚡ icon showing critical bug count")
            if not has_timestamp_paragraph:
                missing.append("bold paragraph with 'Last triaged:' timestamp")
        
            if missing:
                errors.append(f"[X] Hot Fixes section is missing: {', '.join(missing)}")
            else:
                checks_passed.append(f"[C] Hot Fixes section is has")
        
            return TaskScore(
                score=1.0 if len(errors) == 0 else 0.0,
                metadata=ScoreMetadata(
                    success_accumulator=list(dict.fromkeys(checks_passed)),
                    error_accumulator=list(dict.fromkeys(errors)),
                )
            )
    
        except Exception as e:
            errors.append(f"[X] Error validating hot fixes section: {str(e)}")
            return TaskScore(
                score=0.0,
                metadata=ScoreMetadata(
                    success_accumulator=list(dict.fromkeys(checks_passed)),
                    error_accumulator=list(dict.fromkeys(errors)),
                )
            )

    # -----------------------------------------------------------------------------
    # reorganize-guidelines-by-color-v2
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_reorganize_guidelines_by_color(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate that the agent reorganized guidelines by callout color.
    
    Success criteria:
    1. heading_2 '🎨 Guidelines by Category' after main heading
    2. Each color section has heading_3 with '[COLOR] Guidelines ([COUNT])'
    3. All callouts are grouped under their color category
    4. Purple summary callout at end with totals and most common type
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    try:
        try:
            # Find Project Guidelines & Best Practices page
            guidelines_pages = _get_pages(backend, "Project Guidelines & Best Practices")
        
            if not guidelines_pages:
                errors.append("[X] Project Guidelines & Best Practices page not found")
            else:
                checks_passed.append("[C] Project Guidelines & Best Practices page found")
        
            guidelines_page = guidelines_pages[0]
            page_id = guidelines_page.get("_id")
        
            # Get blocks from the page
            blocks = _get_blocks(backend, page_id)
            if not blocks:
                errors.append("[X] Project Guidelines & Best Practices page has no content blocks")
            else:
                checks_passed.append("[C] Project Guidelines & Best Practices page has content blocks")
        
            # Expected color order
            color_order = ['yellow', 'red', 'green', 'blue', 'orange', 'gray']
        
            # Find key elements
            has_category_heading = False
            category_heading_index = -1
            main_heading_index = -1
            color_sections = {}
            has_purple_summary = False
            has_divider_before_summary = False
        
            # Count callouts by color
            callout_counts = {}
            total_callouts = 0
        
            for i, block in enumerate(blocks):
                block_type = block.get("type", "")
                content = block.get("content", "")
                properties = block.get("properties", {})
            
                # Find main heading
                if block_type == "heading1":
                    main_heading_index = i
            
                # Find Guidelines by Category heading
                if block_type == "heading2" and "Guidelines by Category" in content and "🎨" in content:
                    has_category_heading = True
                    category_heading_index = i
            
                # Find color section headings
                if block_type == "heading3" and "Guidelines" in content:
                    for color in color_order:
                        if color.capitalize() in content or color.upper() in content:
                            # Extract count from heading like "Yellow Guidelines (3)"
                            color_sections[color] = i
            
                # Count callouts
                if block_type == "callout":
                    bg_color = properties.get("backgroundColor", "").lower()
                    # Extract base color from "xxx_background"
                    base_color = bg_color.replace("_background", "")
                
                    if "purple" in base_color:
                        # Check if this is the summary callout
                        if "Total Guidelines" in content:
                            has_purple_summary = True
                    else:
                        total_callouts += 1
                        if base_color not in callout_counts:
                            callout_counts[base_color] = 0
                        callout_counts[base_color] += 1
            
                # Check for divider near end
                if block_type == "divider":
                    has_divider_before_summary = True
        
            # Verify category heading position
            if category_heading_index != -1 and main_heading_index != -1:
                if category_heading_index <= main_heading_index:
                    errors.append("[X] Guidelines by Category heading must appear AFTER the main heading")
                else:
                    checks_passed.append("[C] Guidelines by Category heading must appear AFTER the main heading")
        
            # Check for color sections with counts
            missing_sections = []
            for color in color_order:
                if color in callout_counts and callout_counts[color] > 0:
                    if color not in color_sections:
                        missing_sections.append(f"{color.capitalize()} section")
        
            # Check all requirements
            missing = []
            if not has_category_heading:
                missing.append("heading_2 '🎨 Guidelines by Category'")
            if missing_sections:
                missing.extend(missing_sections)
            if not has_divider_before_summary:
                missing.append("divider before summary")
            if not has_purple_summary:
                missing.append("purple summary callout with totals")
        
            if missing:
                errors.append(f"[X] Guidelines reorganization is missing: {', '.join(missing)}")
            else:
                checks_passed.append(f"[C] Guidelines reorganization is has")
        
            # Find most common color
            most_common = max(callout_counts.items(), key=lambda x: x[1]) if callout_counts else ("none", 0)
        
            return TaskScore(
                score=1.0 if len(errors) == 0 else 0.0,
                metadata=ScoreMetadata(
                    success_accumulator=list(dict.fromkeys(checks_passed)),
                    error_accumulator=list(dict.fromkeys(errors)),
                )
            )
    
        except Exception as e:
            errors.append(f"[X] Error validating guidelines reorganization: {str(e)}")
            return TaskScore(
                score=0.0,
                metadata=ScoreMetadata(
                    success_accumulator=list(dict.fromkeys(checks_passed)),
                    error_accumulator=list(dict.fromkeys(errors)),
                )
            )

    # -----------------------------------------------------------------------------
    # add-api-rate-limiting-section-v2
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_add_api_rate_limiting_section(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate that the agent added a Rate Limiting section to API Documentation.
    
    Success criteria:
    1. heading_2 '🔐 Rate Limiting' between Authentication and Endpoints sections
    2. Paragraph about rate limiting
    3. Code block with JSON rate limit config
    4. Yellow callout with ⚠️ icon about 429 responses
    5. Endpoint items updated with HTTP methods
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    try:
        try:
            # Find API Documentation page
            api_pages = _get_pages(backend, "API Documentation")
        
            if not api_pages:
                errors.append("[X] API Documentation page not found")
            else:
                checks_passed.append("[C] API Documentation page found")
        
            api_page = api_pages[0]
            page_id = api_page.get("_id")
        
            # Get blocks from the page
            blocks = _get_blocks(backend, page_id)
            if not blocks:
                errors.append("[X] API Documentation page has no content blocks")
            else:
                checks_passed.append("[C] API Documentation page has content blocks")
        
            # Find key positions
            auth_section_index = -1
            rate_limiting_index = -1
            endpoints_index = -1
        
            has_rate_limiting_heading = False
            has_rate_limit_paragraph = False
            has_json_code_block = False
            has_yellow_callout = False
            has_http_methods_in_endpoints = False
        
            http_methods = ['GET', 'POST', 'PUT', 'DELETE', 'PATCH']
        
            for i, block in enumerate(blocks):
                block_type = block.get("type", "")
                content = block.get("content", "")
                properties = block.get("properties", {})
            
                # Find Authentication heading
                if block_type == "heading2" and "Authentication" in content:
                    auth_section_index = i
            
                # Find Rate Limiting heading
                if block_type == "heading2" and "Rate Limiting" in content and "🔐" in content:
                    has_rate_limiting_heading = True
                    rate_limiting_index = i
            
                # Find Endpoints heading
                if block_type == "heading2" and "Endpoints" in content:
                    endpoints_index = i
            
                # Find rate limiting paragraph
                if block_type == "paragraph":
                    if "rate" in content.lower() and "limit" in content.lower():
                        has_rate_limit_paragraph = True
            
                # Find JSON code block with rate limit config
                if block_type == "code":
                    language = properties.get("language", "").lower()
                    if "json" in language:
                        if "rate_limit" in content or "requests_per" in content:
                            has_json_code_block = True
            
                # Find yellow callout about 429
                if block_type == "callout":
                    bg_color = properties.get("backgroundColor", "").lower()
                    icon = properties.get("icon", "")
                    if "yellow" in bg_color and "⚠️" in icon:
                        if "429" in content or "rate limit" in content.lower():
                            has_yellow_callout = True
            
                # Check numbered list items for HTTP methods
                if block_type == "numberedList":
                    for method in http_methods:
                        if method in content:
                            has_http_methods_in_endpoints = True
                            break
        
            # Verify positioning: Rate Limiting must be between Authentication and Endpoints
            if rate_limiting_index != -1:
                if auth_section_index != -1 and rate_limiting_index <= auth_section_index:
                    errors.append("[X] Rate Limiting section must appear AFTER Authentication section")
                else:
                    checks_passed.append("[C] Rate Limiting section must appear AFTER Authentication section")
                if endpoints_index != -1 and rate_limiting_index >= endpoints_index:
                    errors.append("[X] Rate Limiting section must appear BEFORE Endpoints section")
                else:
                    checks_passed.append("[C] Rate Limiting section must appear BEFORE Endpoints section")
        
            # Check all requirements
            missing = []
            if not has_rate_limiting_heading:
                missing.append("heading_2 '🔐 Rate Limiting'")
            if not has_rate_limit_paragraph:
                missing.append("paragraph about rate limiting")
            if not has_json_code_block:
                missing.append("JSON code block with rate limit config")
            if not has_yellow_callout:
                missing.append("yellow callout with ⚠️ icon about 429 responses")
            if not has_http_methods_in_endpoints:
                missing.append("HTTP methods in endpoint list items")
        
            if missing:
                errors.append(f"[X] API Rate Limiting section is missing: {', '.join(missing)}")
            else:
                checks_passed.append(f"[C] API Rate Limiting section is has")
        
            return TaskScore(
                score=1.0 if len(errors) == 0 else 0.0,
                metadata=ScoreMetadata(
                    success_accumulator=list(dict.fromkeys(checks_passed)),
                    error_accumulator=list(dict.fromkeys(errors)),
                )
            )
    
        except Exception as e:
            errors.append(f"[X] Error validating API rate limiting section: {str(e)}")
            return TaskScore(
                score=0.0,
                metadata=ScoreMetadata(
                    success_accumulator=list(dict.fromkeys(checks_passed)),
                    error_accumulator=list(dict.fromkeys(errors)),
                )
            )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_agent_create_meeting_analysis_report(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate that the agent created a Meeting Analysis Report with content metrics.
    
    Success criteria:
    1. 'Meeting Analysis Report' page exists as child of 'Meeting Notes'
    2. Contains heading1 '📋 Meeting Analysis Report'
    3. Has heading2 '📅 Meeting Overview'
    4. Each meeting has heading3 with title + Gray callout showing block/todo/completion stats
    5. Has heading2 '🔍 Cross-Meeting Insights'
    6. Has numbered list with total meetings, combined blocks, completion rate, most content-heavy
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    try:
        try:
            # Find Meeting Notes page
            meeting_notes_pages = _get_pages(backend, "Meeting Notes")
        
            if not meeting_notes_pages:
                errors.append("[X] Meeting Notes page not found")
            else:
                checks_passed.append("[C] Meeting Notes page found")
        
            meeting_notes_page = meeting_notes_pages[0]
            meeting_notes_id = meeting_notes_page.get("_id")
        
            # Find Meeting Analysis Report page
            report_pages = _get_pages(backend, "Meeting Analysis Report")
        
            if not report_pages:
                errors.append("[X] Meeting Analysis Report page not found")
            else:
                checks_passed.append("[C] Meeting Analysis Report page found")
        
            report_page = report_pages[0]
            report_parent_id = report_page.get("parentId") or report_page.get("parent_id")
        
            # Check if Report is child of Meeting Notes
            if report_parent_id != meeting_notes_id:
                errors.append(f"[X] Meeting Analysis Report is not a child of Meeting Notes (parent: {report_parent_id}, expected: {meeting_notes_id})")
            else:
                checks_passed.append(f"[C] Meeting Analysis Report is a child of Meeting Notes (parent: {report_parent_id}, expected: {meeting_notes_id})")
        
            # Get blocks from Meeting Analysis Report page
            blocks = _get_blocks(backend, report_page.get("_id"))
            if not blocks:
                errors.append("[X] Meeting Analysis Report page has no content blocks")
            else:
                checks_passed.append("[C] Meeting Analysis Report page has content blocks")
        
            # Validate required components
            has_main_heading = False
            has_overview_heading = False
            has_insights_heading = False
            meeting_heading3_count = 0
            gray_callout_count = 0
            has_total_meetings_item = False
            has_combined_blocks_item = False
            has_completion_rate_item = False
            has_most_content_item = False
        
            for block in blocks:
                block_type = block.get("type", "")
                content = block.get("content", "")
                properties = block.get("properties", {})
            
                # Check heading1 '📋 Meeting Analysis Report'
                if block_type == "heading1" and "Meeting Analysis Report" in content and "📋" in content:
                    has_main_heading = True
            
                # Check heading2 '📅 Meeting Overview'
                if block_type == "heading2" and "Meeting Overview" in content and "📅" in content:
                    has_overview_heading = True
            
                # Check heading2 '🔍 Cross-Meeting Insights'
                if block_type == "heading2" and "Cross-Meeting Insights" in content and "🔍" in content:
                    has_insights_heading = True
            
                # Check heading3 for meetings (Sprint Planning, Team Retrospective)
                if block_type == "heading3":
                    if "Sprint Planning" in content or "Team Retrospective" in content:
                        meeting_heading3_count += 1
            
                # Check Gray callout with stats
                if block_type == "callout":
                    bg_color = properties.get("backgroundColor", "")
                    if "gray" in bg_color.lower():
                        if "Total blocks:" in content and "To-do items:" in content and "Completed:" in content:
                            gray_callout_count += 1
            
                # Check numbered list items for insights
                if block_type == "numberedList":
                    content_lower = content.lower()
                    if "total meetings analyzed" in content_lower:
                        has_total_meetings_item = True
                    if "combined block count" in content_lower:
                        has_combined_blocks_item = True
                    if "completion rate" in content_lower or "to-do completion" in content_lower:
                        has_completion_rate_item = True
                    if "most content" in content_lower or "content-heavy" in content_lower:
                        has_most_content_item = True
        
            # Check all requirements
            missing = []
            if not has_main_heading:
                missing.append("heading1 '📋 Meeting Analysis Report'")
            if not has_overview_heading:
                missing.append("heading2 '📅 Meeting Overview'")
            if meeting_heading3_count < 2:
                missing.append(f"heading3 for each meeting (found {meeting_heading3_count}, need 2)")
            if gray_callout_count < 2:
                missing.append(f"Gray callouts with stats for each meeting (found {gray_callout_count}, need 2)")
            if not has_insights_heading:
                missing.append("heading2 '🔍 Cross-Meeting Insights'")
            if not has_total_meetings_item:
                missing.append("numbered list item with total meetings analyzed")
            if not has_combined_blocks_item:
                missing.append("numbered list item with combined block count")
            if not has_completion_rate_item:
                missing.append("numbered list item with overall completion rate")
            if not has_most_content_item:
                missing.append("numbered list item identifying most content-heavy meeting")
        
            if missing:
                errors.append(f"[X] Meeting Analysis Report is missing: {', '.join(missing)}")
            else:
                checks_passed.append(f"[C] Meeting Analysis Report is has")
        
            return TaskScore(
                score=1.0 if len(errors) == 0 else 0.0,
                metadata=ScoreMetadata(
                    success_accumulator=list(dict.fromkeys(checks_passed)),
                    error_accumulator=list(dict.fromkeys(errors)),
                )
            )
        
        except Exception as e:
            errors.append(f"[X] Error validating meeting analysis report: {str(e)}")
            return TaskScore(
                score=0.0,
                metadata=ScoreMetadata(
                    success_accumulator=list(dict.fromkeys(checks_passed)),
                    error_accumulator=list(dict.fromkeys(errors)),
                )
            )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_agent_add_urgent_priority_section(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate that the agent added an Urgent Priority section to the Bug Tracker page.
    
    Success criteria:
    1. heading_2 '🔥 Urgent - Requires Immediate Action' after Critical Bugs but before Medium Priority
    2. Three unchecked todos with exact texts about payment, database, and auth issues
    3. Red callout with 🚨 icon about 24-hour resolution
    4. Updated paragraph with ' - Last priority update: [date]' appended
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    try:
        try:
            # Find Bug Tracker page
            bug_tracker_pages = _get_pages(backend, "Bug Tracker")
        
            if not bug_tracker_pages:
                errors.append("[X] Bug Tracker page not found")
            else:
                checks_passed.append("[C] Bug Tracker page found")
        
            bug_tracker_page = bug_tracker_pages[0]
            page_id = bug_tracker_page.get("_id")
        
            # Get blocks from the page
            blocks = _get_blocks(backend, page_id)
            if not blocks:
                errors.append("[X] Bug Tracker page has no content blocks")
            else:
                checks_passed.append("[C] Bug Tracker page has content blocks")
        
            # Find key positions
            critical_bugs_index = -1
            urgent_section_index = -1
            medium_priority_index = -1
        
            has_urgent_heading = False
            has_red_callout = False
            has_updated_paragraph = False
            urgent_todos = []
        
            expected_todo_keywords = [
                "payment processing timeout",
                "database connection pooling",
                "authentication vulnerability"
            ]
        
            for i, block in enumerate(blocks):
                block_type = block.get("type", "")
                content = block.get("content", "")
                properties = block.get("properties", {})
            
                # Find Critical Bugs heading
                if block_type == "heading2" and "Critical" in content:
                    critical_bugs_index = i
            
                # Find Urgent section heading
                if block_type == "heading2" and "Urgent" in content and "🔥" in content:
                    has_urgent_heading = True
                    urgent_section_index = i
            
                # Find Medium Priority heading
                if block_type == "heading2" and "Medium" in content:
                    medium_priority_index = i
            
                # Find unchecked todos with expected keywords
                if block_type == "todo":
                    checked = properties.get("checked", False)
                    content_lower = content.lower()
                    for keyword in expected_todo_keywords:
                        if keyword in content_lower and not checked:
                            urgent_todos.append(content)
            
                # Find red callout with 🚨 icon
                if block_type == "callout":
                    bg_color = properties.get("backgroundColor", "")
                    icon = properties.get("icon", "")
                    if "red" in bg_color.lower() and "🚨" in icon:
                        if "24 hours" in content.lower() or "resolved" in content.lower():
                            has_red_callout = True
            
                # Check paragraph for updated text
                if block_type == "paragraph":
                    if "Track and manage bugs" in content and "priority update" in content.lower():
                        has_updated_paragraph = True
        
            # Verify positioning
            if urgent_section_index != -1:
                if critical_bugs_index != -1 and urgent_section_index <= critical_bugs_index:
                    errors.append("[X] Urgent section must appear AFTER Critical Bugs section")
                else:
                    checks_passed.append("[C] Urgent section must appear AFTER Critical Bugs section")
                if medium_priority_index != -1 and urgent_section_index >= medium_priority_index:
                    errors.append("[X] Urgent section must appear BEFORE Medium Priority section")
                else:
                    checks_passed.append("[C] Urgent section must appear BEFORE Medium Priority section")
        
            # Check all requirements
            missing = []
            if not has_urgent_heading:
                missing.append("heading_2 '🔥 Urgent - Requires Immediate Action'")
            if len(urgent_todos) < 3:
                missing.append(f"3 unchecked todos with required keywords (found {len(urgent_todos)})")
            if not has_red_callout:
                missing.append("red callout with 🚨 icon about 24-hour resolution")
            if not has_updated_paragraph:
                missing.append("updated paragraph with 'Last priority update' text")
        
            if missing:
                errors.append(f"[X] Urgent Priority section is missing: {', '.join(missing)}")
            else:
                checks_passed.append(f"[C] Urgent Priority section is has")
        
            return TaskScore(
                score=1.0 if len(errors) == 0 else 0.0,
                metadata=ScoreMetadata(
                    success_accumulator=list(dict.fromkeys(checks_passed)),
                    error_accumulator=list(dict.fromkeys(errors)),
                )
            )
    
        except Exception as e:
            errors.append(f"[X] Error validating urgent priority section: {str(e)}")
            return TaskScore(
                score=0.0,
                metadata=ScoreMetadata(
                    success_accumulator=list(dict.fromkeys(checks_passed)),
                    error_accumulator=list(dict.fromkeys(errors)),
                )
            )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_agent_add_utility_functions_section_2(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate that the agent added a Utility Functions section to Code Examples Repository.
    
    Success criteria:
    1. heading_2 '🔧 Utility Functions' exists
    2. Paragraph 'Essential helper functions for common tasks.'
    3. Three code blocks with exact languages: javascript, python, typescript
    4. Gray callout with 💡 icon about @company/utils
    5. Final italic paragraph with correct code block count
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    try:
        try:
            # Find Code Examples Repository page
            code_pages = _get_pages(backend, "Code Examples Repository")
        
            if not code_pages:
                errors.append("[X] Code Examples Repository page not found")
            else:
                checks_passed.append("[C] Code Examples Repository page found")
        
            code_page = code_pages[0]
            page_id = code_page.get("_id")
        
            # Get blocks from the page
            blocks = _get_blocks(backend, page_id)
            if not blocks:
                errors.append("[X] Code Examples Repository page has no content blocks")
            else:
                checks_passed.append("[C] Code Examples Repository page has content blocks")
        
            # Validate required components
            has_utility_heading = False
            has_helper_paragraph = False
            has_js_code = False
            has_python_code = False
            has_ts_code = False
            has_gray_callout = False
            has_count_paragraph = False
        
            total_code_blocks = 0
        
            for block in blocks:
                block_type = block.get("type", "")
                content = block.get("content", "")
                properties = block.get("properties", {})
            
                # Count all code blocks
                if block_type == "code":
                    total_code_blocks += 1
                    language = properties.get("language", "").lower()
                
                    # Check for specific code blocks
                    if language == "javascript" and "formatDate" in content:
                        has_js_code = True
                    if language == "python" and "validate_email" in content:
                        has_python_code = True
                    if language == "typescript" and "interface User" in content:
                        has_ts_code = True
            
                # Check heading_2 for Utility Functions
                if block_type == "heading2" and "Utility Functions" in content and "🔧" in content:
                    has_utility_heading = True
            
                # Check helper paragraph
                if block_type == "paragraph":
                    if "Essential helper functions" in content or "helper functions" in content.lower():
                        has_helper_paragraph = True
                    # Check count paragraph at bottom
                    if "code examples" in content.lower() and "repository" in content.lower():
                        if "italic" in str(properties).lower() or properties.get("italic"):
                            has_count_paragraph = True
                        # Also accept if it just has the count text
                        if str(total_code_blocks) in content or "contains" in content.lower():
                            has_count_paragraph = True
            
                # Check gray callout with 💡 icon
                if block_type == "callout":
                    bg_color = properties.get("backgroundColor", "")
                    icon = properties.get("icon", "")
                    if "gray" in bg_color.lower() and "💡" in icon:
                        if "@company/utils" in content or "shared library" in content.lower():
                            has_gray_callout = True
        
            # Check all requirements
            missing = []
            if not has_utility_heading:
                missing.append("heading_2 '🔧 Utility Functions'")
            if not has_helper_paragraph:
                missing.append("paragraph about helper functions")
            if not has_js_code:
                missing.append("JavaScript code block with formatDate")
            if not has_python_code:
                missing.append("Python code block with validate_email")
            if not has_ts_code:
                missing.append("TypeScript code block with User interface")
            if not has_gray_callout:
                missing.append("gray callout with 💡 icon about @company/utils")
            if not has_count_paragraph:
                missing.append("italic paragraph with code block count")
        
            if missing:
                errors.append(f"[X] Utility Functions section is missing: {', '.join(missing)}")
            else:
                checks_passed.append(f"[C] Utility Functions section is has")
        
            return TaskScore(
                score=1.0 if len(errors) == 0 else 0.0,
                metadata=ScoreMetadata(
                    success_accumulator=list(dict.fromkeys(checks_passed)),
                    error_accumulator=list(dict.fromkeys(errors)),
                )
            )
    
        except Exception as e:
            errors.append(f"[X] Error validating utility functions section: {str(e)}")
            return TaskScore(
                score=0.0,
                metadata=ScoreMetadata(
                    success_accumulator=list(dict.fromkeys(checks_passed)),
                    error_accumulator=list(dict.fromkeys(errors)),
                )
            )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_agent_add_performance_reviews_section(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate that the agent added a Performance Reviews section to the Company Handbook page.
    
    Success criteria:
    1. heading_3 'Performance Reviews' appears after Time Off paragraph but before Benefits heading
    2. Paragraph with exact text about quarterly performance reviews
    3. Numbered list with exactly 3 items in specified order
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    try:
        try:
            # Find Company Handbook page
            handbook_pages = _get_pages(backend, "Company Handbook")
        
            if not handbook_pages:
                errors.append("[X] Company Handbook page not found")
            else:
                checks_passed.append("[C] Company Handbook page found")
        
            handbook_page = handbook_pages[0]
            page_id = handbook_page.get("_id")
        
            # Get blocks from the page
            blocks = _get_blocks(backend, page_id)
            if not blocks:
                errors.append("[X] Company Handbook page has no content blocks")
            else:
                checks_passed.append("[C] Company Handbook page has content blocks")
        
            # Find key positions
            time_off_paragraph_index = -1
            performance_reviews_index = -1
            benefits_heading_index = -1
        
            has_performance_heading = False
            has_quarterly_paragraph = False
            numbered_list_items = []
        
            expected_list_items = [
                "360-degree feedback from peers and managers",
                "Goal setting and achievement tracking",
                "Career development planning sessions"
            ]
        
            for i, block in enumerate(blocks):
                block_type = block.get("type", "")
                content = block.get("content", "")
            
                # Find Time Off paragraph (the one about unlimited PTO)
                if block_type == "paragraph" and "unlimited PTO" in content:
                    time_off_paragraph_index = i
            
                # Find Performance Reviews heading
                if block_type == "heading3" and "Performance Reviews" in content:
                    has_performance_heading = True
                    performance_reviews_index = i
            
                # Find Benefits heading
                if block_type == "heading2" and "Benefits" in content:
                    benefits_heading_index = i
            
                # Find the quarterly reviews paragraph
                if block_type == "paragraph" and "quarterly performance reviews" in content.lower():
                    if "continuous growth" in content.lower() and "feedback" in content.lower():
                        has_quarterly_paragraph = True
            
                # Collect numbered list items (only after Performance Reviews heading if found)
                if block_type == "numberedList":
                    if performance_reviews_index != -1 and i > performance_reviews_index:
                        if benefits_heading_index == -1 or i < benefits_heading_index:
                            numbered_list_items.append(content)
        
            # Validate positioning
            if not has_performance_heading:
                errors.append("[X] Performance Reviews section is missing: heading_3 'Performance Reviews'")
            else:
                checks_passed.append("[C] Performance Reviews section is has: heading_3 'Performance Reviews'")
        
            if time_off_paragraph_index == -1:
                errors.append("[X] Could not find Time Off paragraph to validate positioning")
            else:
                checks_passed.append("[C] Could find Time Off paragraph to validate positioning")
        
            if benefits_heading_index == -1:
                errors.append("[X] Could not find Benefits heading to validate positioning")
            else:
                checks_passed.append("[C] Could find Benefits heading to validate positioning")
        
            # Check ordering: Time Off paragraph < Performance Reviews < Benefits heading
            if not (time_off_paragraph_index < performance_reviews_index < benefits_heading_index):
                errors.append(f"[X] Performance Reviews section is not correctly positioned (must be after Time Off paragraph and before Benefits heading)")
            else:
                checks_passed.append(f"[C] Performance Reviews section is correctly positioned (must be after Time Off paragraph and before Benefits heading)")
        
            if not has_quarterly_paragraph:
                errors.append("[X] Performance Reviews section is missing: paragraph about quarterly performance reviews")
            else:
                checks_passed.append("[C] Performance Reviews section is has: paragraph about quarterly performance reviews")
        
            # Validate numbered list items
            found_items = 0
            for expected_item in expected_list_items:
                for actual_item in numbered_list_items:
                    if expected_item.lower() in actual_item.lower():
                        found_items += 1
                        break
        
            if found_items != 3:
                errors.append(f"[X] Performance Reviews section is missing: expected 3 numbered list items, found {found_items} matching items")
            else:
                checks_passed.append(f"[C] Performance Reviews section is has: Found 3 numbered list items as expected")
        
            return TaskScore(
                score=1.0 if len(errors) == 0 else 0.0,
                metadata=ScoreMetadata(
                    success_accumulator=list(dict.fromkeys(checks_passed)),
                    error_accumulator=list(dict.fromkeys(errors)),
                )
            )
        
        except Exception as e:
            errors.append(f"[X] Error validating Performance Reviews section: {str(e)}")
            return TaskScore(
                score=0.0,
                metadata=ScoreMetadata(
                    success_accumulator=list(dict.fromkeys(checks_passed)),
                    error_accumulator=list(dict.fromkeys(errors)),
                )
            )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_agent_create_architecture_summary_report(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate that the agent created an Architecture Summary Report page under Project Documentation.
    
    Success criteria:
    1. Page 'Architecture Summary Report' exists as child of 'Project Documentation'
    2. Contains heading_1 '🏛️ Architecture Documentation Overview'
    3. Contains heading_2 '📊 Content Statistics'
    4. Paragraph with total sections count
    5. For each architecture section, heading_3 with '🔍 [section name]' and bulleted list with block counts
    6. Contains heading_2 '🎯 Documentation Completeness'
    7. Green callout with completion percentage
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    try:
        try:
            # Find Project Documentation page
            proj_doc_pages = _get_pages(backend, "Project Documentation")
            if not proj_doc_pages:
                errors.append("[X] Project Documentation page not found")
            else:
                checks_passed.append("[C] Project Documentation page found")
            proj_doc_id = proj_doc_pages[0].get("_id")
        
            # Find Architecture Summary Report page
            report_pages = _get_pages(backend, "Architecture Summary Report")
            if not report_pages:
                errors.append("[X] Architecture Summary Report page not found")
            else:
                checks_passed.append("[C] Architecture Summary Report page found")
        
            report_page = report_pages[0]
            report_parent_id = report_page.get("parentId") or report_page.get("parent_id")
        
            # Check if report is child of Project Documentation
            if report_parent_id != proj_doc_id:
                errors.append(f"[X] Architecture Summary Report is not a child of Project Documentation")
            else:
                checks_passed.append(f"[C] Architecture Summary Report is a child of Project Documentation")
        
            page_id = report_page.get("_id")
            blocks = _get_blocks(backend, page_id)
            if not blocks:
                errors.append("[X] Architecture Summary Report page has no content blocks")
            else:
                checks_passed.append("[C] Architecture Summary Report page has content blocks")
        
            # Validate required headings
            has_main_heading = False
            has_stats_heading = False
            has_completeness_heading = False
            has_total_paragraph = False
            has_green_callout = False
            section_headings_found = []
        
            for block in blocks:
                block_type = block.get("type", "")
                content = block.get("content", "")
                properties = block.get("properties", {})
            
                # Check main heading
                if block_type == "heading1" and "Architecture Documentation Overview" in content and "🏛️" in content:
                    has_main_heading = True
            
                # Check stats heading
                if block_type == "heading2" and "Content Statistics" in content and "📊" in content:
                    has_stats_heading = True
            
                # Check completeness heading
                if block_type == "heading2" and "Documentation Completeness" in content and "🎯" in content:
                    has_completeness_heading = True
            
                # Check total sections paragraph
                if block_type == "paragraph" and "Total documentation sections analyzed" in content:
                    has_total_paragraph = True
            
                # Check section headings with 🔍
                if block_type == "heading3" and "🔍" in content:
                    section_headings_found.append(content)
            
                # Check green callout with completion percentage
                if block_type == "callout":
                    bg_color = properties.get("backgroundColor", "")
                    if "green" in bg_color.lower() and "completion" in content.lower() and "%" in content:
                        has_green_callout = True
        
            # Check all requirements
            missing = []
            if not has_main_heading:
                missing.append("heading_1 '🏛️ Architecture Documentation Overview'")
            if not has_stats_heading:
                missing.append("heading_2 '📊 Content Statistics'")
            if not has_total_paragraph:
                missing.append("paragraph with total sections count")
            if len(section_headings_found) < 2:
                missing.append(f"section headings with 🔍 emoji (found {len(section_headings_found)}, need at least 2)")
            if not has_completeness_heading:
                missing.append("heading_2 '🎯 Documentation Completeness'")
            if not has_green_callout:
                missing.append("green callout with completion percentage")
        
            if missing:
                errors.append(f"[X] Architecture Summary Report is missing: {', '.join(missing)}")
            else:
                checks_passed.append(f"[C] Architecture Summary Report is has")
        
            return TaskScore(
                score=1.0 if len(errors) == 0 else 0.0,
                metadata=ScoreMetadata(
                    success_accumulator=list(dict.fromkeys(checks_passed)),
                    error_accumulator=list(dict.fromkeys(errors)),
                )
            )
        
        except Exception as e:
            errors.append(f"[X] Error validating Architecture Summary Report: {str(e)}")
            return TaskScore(
                score=0.0,
                metadata=ScoreMetadata(
                    success_accumulator=list(dict.fromkeys(checks_passed)),
                    error_accumulator=list(dict.fromkeys(errors)),
                )
            )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_agent_add_tutorial_enhancement_system(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate that the agent implemented a tutorial enhancement system on the Getting Started page.
    
    Success criteria:
    1. heading_2 '🎯 Quick Start Progress Tracker' exists after main title
    2. Progress callout with correct color (red/yellow/green) based on completion percentage
    3. heading_3 '📋 Your Learning Path' with numbered list of todos grouped by status
    4. heading_2 '💡 Pro Tips' with exactly 3 blue callouts
    5. Divider followed by bookmark to help.notion.com
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    try:
        try:
            # Find Getting Started page
            getting_started_pages = _get_pages(backend, "Getting Started")
            if not getting_started_pages:
                errors.append("[X] Getting Started page not found")
            else:
                checks_passed.append("[C] Getting Started page found")
        
            page_id = getting_started_pages[0].get("_id")
            blocks = _get_blocks(backend, page_id)
            if not blocks:
                errors.append("[X] Getting Started page has no content blocks")
            else:
                checks_passed.append("[C] Getting Started page has content blocks")
        
            # Count todos for progress calculation
            total_todos = 0
            checked_todos = 0
            for block in blocks:
                if block.get("type") == "todo":
                    total_todos += 1
                    if block.get("properties", {}).get("checked"):
                        checked_todos += 1
        
            # Calculate expected percentage
            percentage = (checked_todos / total_todos * 100) if total_todos > 0 else 0
        
            # Validate required components
            has_progress_tracker_heading = False
            has_progress_callout = False
            has_learning_path_heading = False
            has_pro_tips_heading = False
            blue_tip_callouts = 0
            has_divider = False
            has_bookmark = False
        
            for i, block in enumerate(blocks):
                block_type = block.get("type", "")
                content = block.get("content", "")
                properties = block.get("properties", {})
            
                # Check progress tracker heading
                if block_type == "heading2" and "Quick Start Progress Tracker" in content and "🎯" in content:
                    has_progress_tracker_heading = True
            
                # Check progress callout with correct color
                if block_type == "callout":
                    bg_color = properties.get("backgroundColor", "")
                    if "complete" in content.lower() and "%" in content:
                        # Check if color matches percentage range
                        if percentage <= 25 and "red" in bg_color.lower():
                            has_progress_callout = True
                        elif 26 <= percentage <= 75 and "yellow" in bg_color.lower():
                            has_progress_callout = True
                        elif percentage >= 76 and "green" in bg_color.lower():
                            has_progress_callout = True
                
                    # Count blue tip callouts
                    if "blue" in bg_color.lower() and "Tip" in content:
                        blue_tip_callouts += 1
            
                # Check learning path heading
                if block_type == "heading3" and "Your Learning Path" in content and "📋" in content:
                    has_learning_path_heading = True

                # Check pro tips heading
                if block_type == "heading2" and "Pro Tips" in content and "💡" in content:
                    has_pro_tips_heading = True
            
                # Check divider
                if block_type == "divider":
                    has_divider = True
            
                # Check bookmark
                if block_type == "bookmark":
                    url = properties.get("url", "") or content
                    if "notion.com" in url.lower() or "help.notion" in content.lower():
                        has_bookmark = True
        
            # Validate all requirements
            missing = []
            if not has_progress_tracker_heading:
                missing.append("heading_2 '🎯 Quick Start Progress Tracker'")
            if not has_progress_callout:
                missing.append(f"progress callout with correct color for {percentage:.0f}%")
            if not has_learning_path_heading:
                missing.append("heading_3 '📋 Your Learning Path'")
            if not has_pro_tips_heading:
                missing.append("heading_2 '💡 Pro Tips'")
            if blue_tip_callouts < 3:
                missing.append(f"3 blue tip callouts (found {blue_tip_callouts})")
            if not has_divider:
                missing.append("divider before bookmark")
            if not has_bookmark:
                missing.append("bookmark to help.notion.com")
        
            if missing:
                errors.append(f"[X] Tutorial enhancement system is missing: {', '.join(missing)}")
            else:
                checks_passed.append(f"[C] Tutorial enhancement system is has")
        
            return TaskScore(
                score=1.0 if len(errors) == 0 else 0.0,
                metadata=ScoreMetadata(
                    success_accumulator=list(dict.fromkeys(checks_passed)),
                    error_accumulator=list(dict.fromkeys(errors)),
                )
            )
        
        except Exception as e:
            errors.append(f"[X] Error validating tutorial enhancement system: {str(e)}")
            return TaskScore(
                score=0.0,
                metadata=ScoreMetadata(
                    success_accumulator=list(dict.fromkeys(checks_passed)),
                    error_accumulator=list(dict.fromkeys(errors)),
                )
            )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_agent_add_advanced_patterns_section(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate that the agent added an Advanced Patterns section to the Code Examples Repository page.
    
    Success criteria:
    1. heading_2 '🚀 Advanced Patterns' appears after the last existing code block
    2. Paragraph 'The following examples demonstrate production-ready patterns:'
    3. heading_3 '🔄 State Management Example'
    4. JavaScript code block with 'const [state, dispatch] = useReducer(reducer, initialState);'
    5. heading_3 '🌐 API Integration Pattern'
    6. TypeScript code block with 'interface ApiResponse<T> { data: T; error?: Error; }'
    7. Green callout with 💡 icon: 'Pro tip: These patterns are used in our production codebase'
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    try:
        try:
            # Find Code Examples Repository page
            code_pages = _get_pages(backend, "Code Examples Repository")
        
            if not code_pages:
                errors.append("[X] Code Examples Repository page not found")
            else:
                checks_passed.append("[C] Code Examples Repository page found")
        
            code_page = code_pages[0]
            page_id = code_page.get("_id")
        
            # Get blocks from the page
            blocks = _get_blocks(backend, page_id)
            if not blocks:
                errors.append("[X] Code Examples Repository page has no content blocks")
            else:
                checks_passed.append("[C] Code Examples Repository page has content blocks")
        
            # Find last original code block index (before Advanced Patterns section)
            # and track what we need
            advanced_patterns_index = -1
            last_code_block_before_advanced = -1
        
            has_advanced_heading = False
            has_production_paragraph = False
            has_state_mgmt_heading = False
            has_js_code = False
            has_api_heading = False
            has_ts_code = False
            has_green_callout = False
        
            for i, block in enumerate(blocks):
                block_type = block.get("type", "")
                content = block.get("content", "")
                properties = block.get("properties", {})
            
                # Find the Advanced Patterns heading
                if block_type == "heading2" and "Advanced Patterns" in content and "🚀" in content:
                    has_advanced_heading = True
                    advanced_patterns_index = i
            
                # Track code blocks before Advanced Patterns
                if block_type == "code" and advanced_patterns_index == -1:
                    last_code_block_before_advanced = i
            
                # Check production paragraph
                if block_type == "paragraph" and "production-ready patterns" in content.lower():
                    has_production_paragraph = True
            
                # Check State Management heading
                if block_type == "heading3" and "State Management Example" in content and "🔄" in content:
                    has_state_mgmt_heading = True
            
                # Check JavaScript code block
                if block_type == "code":
                    lang = properties.get("language", "").lower()
                    if lang == "javascript" and "useReducer" in content and "dispatch" in content:
                        has_js_code = True
            
                # Check API Integration heading
                if block_type == "heading3" and "API Integration Pattern" in content and "🌐" in content:
                    has_api_heading = True
            
                # Check TypeScript code block
                if block_type == "code":
                    lang = properties.get("language", "").lower()
                    if lang == "typescript" and "ApiResponse" in content and "interface" in content:
                        has_ts_code = True
            
                # Check green callout with pro tip
                if block_type == "callout":
                    bg_color = properties.get("backgroundColor", "")
                    icon = properties.get("icon", "")
                    if "green" in bg_color.lower() and "💡" in icon:
                        if "production codebase" in content.lower() or "pro tip" in content.lower():
                            has_green_callout = True
        
            # Verify positioning
            if advanced_patterns_index != -1 and last_code_block_before_advanced != -1:
                if advanced_patterns_index <= last_code_block_before_advanced:
                    errors.append("[X] Advanced Patterns section must appear AFTER the last existing code block")
                else:
                    checks_passed.append("[C] Advanced Patterns section must appear AFTER the last existing code block")
        
            # Check all requirements
            missing = []
            if not has_advanced_heading:
                missing.append("heading_2 '🚀 Advanced Patterns'")
            if not has_production_paragraph:
                missing.append("paragraph about production-ready patterns")
            if not has_state_mgmt_heading:
                missing.append("heading_3 '🔄 State Management Example'")
            if not has_js_code:
                missing.append("JavaScript code block with useReducer")
            if not has_api_heading:
                missing.append("heading_3 '🌐 API Integration Pattern'")
            if not has_ts_code:
                missing.append("TypeScript code block with ApiResponse interface")
            if not has_green_callout:
                missing.append("green callout with 💡 icon about production codebase")
        
            if missing:
                errors.append(f"[X] Advanced Patterns section is missing: {', '.join(missing)}")
            else:
                checks_passed.append(f"[C] Advanced Patterns section is has")
        
            return TaskScore(
                score=1.0 if len(errors) == 0 else 0.0,
                metadata=ScoreMetadata(
                    success_accumulator=list(dict.fromkeys(checks_passed)),
                    error_accumulator=list(dict.fromkeys(errors)),
                )
            )
    
        except Exception as e:
            errors.append(f"[X] Error validating advanced patterns section: {str(e)}")
            return TaskScore(
                score=0.0,
                metadata=ScoreMetadata(
                    success_accumulator=list(dict.fromkeys(checks_passed)),
                    error_accumulator=list(dict.fromkeys(errors)),
                )
            )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_agent_swap_api_sections_with_security(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate that the agent swapped Authentication and Rate Limiting sections
    and inserted Security Best Practices between them.
    
    Success criteria:
    1. Rate Limiting section appears BEFORE Authentication section
    2. Security Best Practices section (heading_2) is between them
    3. Red callout with ⚠️ icon about API keys
    4. JavaScript code block with exact content
    5. Three numbered list items about security practices
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    try:
        try:
            # Find API Documentation page
            api_pages = _get_pages(backend, "API Documentation")
        
            if not api_pages:
                errors.append("[X] API Documentation page not found")
            else:
                checks_passed.append("[C] API Documentation page found")
        
            api_page = api_pages[0]
            page_id = api_page.get("_id")
        
            # Get blocks from the page
            blocks = _get_blocks(backend, page_id)
            if not blocks:
                errors.append("[X] API Documentation page has no content blocks")
            else:
                checks_passed.append("[C] API Documentation page has content blocks")
        
            # Find key section positions
            rate_limiting_index = -1
            authentication_index = -1
            security_practices_index = -1
        
            has_rate_limiting_section = False
            has_authentication_section = False
            has_security_heading = False
            has_red_callout = False
            has_js_code = False
            numbered_list_items = []
        
            expected_code = "const API_KEY = process.env.API_KEY; // Store in environment variables"
            expected_list_items = [
                "Rotate keys every 90 days",
                "Use IP allowlisting when possible",
                "Monitor for unusual access patterns"
            ]
        
            for i, block in enumerate(blocks):
                block_type = block.get("type", "")
                content = block.get("content", "")
                properties = block.get("properties", {})
            
                # Find Rate Limiting section heading
                if block_type == "heading2" and "Rate Limiting" in content:
                    has_rate_limiting_section = True
                    rate_limiting_index = i
            
                # Find Authentication section heading
                if block_type == "heading2" and "Authentication" in content:
                    has_authentication_section = True
                    authentication_index = i
            
                # Find Security Best Practices heading
                if block_type == "heading2" and "Security Best Practices" in content and "🔒" in content:
                    has_security_heading = True
                    security_practices_index = i
            
                # Check red callout with ⚠️ icon
                if block_type == "callout":
                    bg_color = properties.get("backgroundColor", "")
                    icon = properties.get("icon", "")
                    if "red" in bg_color.lower() and "⚠️" in icon:
                        if "API keys" in content or "client-side code" in content.lower():
                            has_red_callout = True
            
                # Check JavaScript code block
                if block_type == "code":
                    lang = properties.get("language", "").lower()
                    if lang == "javascript":
                        if "process.env.API_KEY" in content or "API_KEY" in content:
                            has_js_code = True
            
                # Collect numbered list items (only between security and auth sections)
                if block_type == "numberedList":
                    if security_practices_index != -1 and authentication_index != -1:
                        if security_practices_index < i < authentication_index:
                            numbered_list_items.append(content)
                    elif security_practices_index != -1:
                        # If auth section not found yet, still collect
                        numbered_list_items.append(content)
        
            # Validate section order: Rate Limiting < Security < Authentication
            if rate_limiting_index == -1:
                errors.append("[X] Rate Limiting section not found")
            else:
                checks_passed.append("[C] Rate Limiting section found")
            if authentication_index == -1:
                errors.append("[X] Authentication section not found")
            else:
                checks_passed.append("[C] Authentication section found")
            if security_practices_index == -1:
                errors.append("[X] Security Best Practices section not found")
            else:
                checks_passed.append("[C] Security Best Practices section found")
        
            # Check order: Rate Limiting must come BEFORE Authentication
            if rate_limiting_index > authentication_index:
                errors.append(f"[X] Rate Limiting section (index {rate_limiting_index}) must appear BEFORE Authentication section (index {authentication_index})")
            else:
                checks_passed.append(f"[C] Rate Limiting section (index {rate_limiting_index}) must appear BEFORE Authentication section (index {authentication_index})")
        
            # Check Security Best Practices is between them
            if not (rate_limiting_index < security_practices_index < authentication_index):
                errors.append(f"[X] Security Best Practices section must be between Rate Limiting and Authentication sections")
            else:
                checks_passed.append(f"[C] Security Best Practices section must be between Rate Limiting and Authentication sections")
        
            # Check all requirements
            missing = []
            if not has_security_heading:
                missing.append("heading_2 '🔒 Security Best Practices'")
            if not has_red_callout:
                missing.append("red callout with ⚠️ icon about API keys")
            if not has_js_code:
                missing.append("JavaScript code block with API_KEY")
        
            # Check numbered list items
            found_items = 0
            for expected_item in expected_list_items:
                for actual_item in numbered_list_items:
                    if expected_item.lower() in actual_item.lower():
                        found_items += 1
                        break
        
            if found_items < 3:
                missing.append(f"3 numbered list items about security practices (found {found_items})")
        
            if missing:
                errors.append(f"[X] API sections swap is missing: {', '.join(missing)}")
            else:
                checks_passed.append(f"[C] API sections swap is has")
        
            return TaskScore(
                score=1.0 if len(errors) == 0 else 0.0,
                metadata=ScoreMetadata(
                    success_accumulator=list(dict.fromkeys(checks_passed)),
                    error_accumulator=list(dict.fromkeys(errors)),
                )
            )
    
        except Exception as e:
            errors.append(f"[X] Error validating API sections swap: {str(e)}")
            return TaskScore(
                score=0.0,
                metadata=ScoreMetadata(
                    success_accumulator=list(dict.fromkeys(checks_passed)),
                    error_accumulator=list(dict.fromkeys(errors)),
                )
            )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_agent_reorganize_team_directory(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate that the agent reorganized the Team Directory page.
    
    Success criteria:
    1. Gray callout with 🌟 icon appears after intro paragraph but before Engineering Team
    2. Each team member entry includes ' | Slack: @firstname' in italics
    3. Team Photo image moved to appear after callout but before Engineering Team
    4. Italic caption about company retreat appears under relocated image
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    try:
        try:
            # Find Team Directory page
            team_pages = _get_pages(backend, "Team Directory")
        
            if not team_pages:
                errors.append("[X] Team Directory page not found")
            else:
                checks_passed.append("[C] Team Directory page found")
        
            team_page = team_pages[0]
            page_id = team_page.get("_id")
        
            # Get blocks from the page
            blocks = _get_blocks(backend, page_id)
            if not blocks:
                errors.append("[X] Team Directory page has no content blocks")
            else:
                checks_passed.append("[C] Team Directory page has content blocks")
        
            # Find key positions and content
            intro_paragraph_index = -1
            gray_callout_index = -1
            image_index = -1
            caption_index = -1
            engineering_heading_index = -1
        
            has_gray_callout = False
            has_correct_callout_content = False
            has_image = False
            has_caption = False
            team_member_entries_with_slack = 0
            total_team_members = 0
        
            for i, block in enumerate(blocks):
                block_type = block.get("type", "")
                content = block.get("content", "")
                properties = block.get("properties", {})
            
                # Find intro paragraph (contains "Meet the amazing people" or similar)
                if block_type == "paragraph":
                    if "amazing people" in content.lower() or "meet" in content.lower():
                        intro_paragraph_index = i
                    # Check for retreat caption
                    if "company retreat" in content.lower() and "2024" in content:
                        if properties.get("italic") or "italic" in str(properties).lower():
                            has_caption = True
                            caption_index = i
            
                # Find gray callout with star icon
                if block_type == "callout":
                    bg_color = properties.get("backgroundColor", "")
                    icon = properties.get("icon", "")
                    if "gray" in bg_color.lower() and "🌟" in icon:
                        has_gray_callout = True
                        gray_callout_index = i
                        if "time zones" in content.lower() and "languages" in content.lower():
                            has_correct_callout_content = True
            
                # Find image block
                if block_type == "image":
                    has_image = True
                    image_index = i
            
                # Find Engineering Team heading
                if block_type == "heading2" and "Engineering" in content:
                    engineering_heading_index = i
            
                # Check team member entries for Slack handle
                if block_type == "bulletedList":
                    total_team_members += 1
                    # Check for Slack handle pattern
                    if "slack:" in content.lower() and "@" in content:
                        team_member_entries_with_slack += 1
        
            # Validate positioning
            missing = []
        
            if not has_gray_callout:
                missing.append("gray callout with 🌟 icon")
            elif not has_correct_callout_content:
                missing.append("callout content about time zones and languages")
        
            # Check callout is after intro but before Engineering
            if gray_callout_index != -1:
                if intro_paragraph_index != -1 and gray_callout_index <= intro_paragraph_index:
                    missing.append("callout must appear AFTER intro paragraph")
                if engineering_heading_index != -1 and gray_callout_index >= engineering_heading_index:
                    missing.append("callout must appear BEFORE Engineering Team heading")
        
            # Check image position (after callout, before Engineering)
            if has_image and image_index != -1:
                if gray_callout_index != -1 and image_index <= gray_callout_index:
                    missing.append("Team Photo must appear AFTER gray callout")
                if engineering_heading_index != -1 and image_index >= engineering_heading_index:
                    missing.append("Team Photo must appear BEFORE Engineering Team heading")
            else:
                missing.append("Team Photo image block")
        
            # Check caption is after image
            if has_caption:
                if image_index != -1 and caption_index <= image_index:
                    missing.append("caption must appear AFTER image")
            else:
                missing.append("italic caption about company retreat")
        
            # Check team member Slack handles
            if total_team_members > 0:
                if team_member_entries_with_slack < total_team_members:
                    missing.append(f"Slack handles for all team members ({team_member_entries_with_slack}/{total_team_members} have handles)")
        
            if missing:
                errors.append(f"[X] Team Directory reorganization is missing: {', '.join(missing)}")
            else:
                checks_passed.append(f"[C] Team Directory reorganization is has")
        
            return TaskScore(
                score=1.0 if len(errors) == 0 else 0.0,
                metadata=ScoreMetadata(
                    success_accumulator=list(dict.fromkeys(checks_passed)),
                    error_accumulator=list(dict.fromkeys(errors)),
                )
            )
    
        except Exception as e:
            errors.append(f"[X] Error validating Team Directory reorganization: {str(e)}")
            return TaskScore(
                score=0.0,
                metadata=ScoreMetadata(
                    success_accumulator=list(dict.fromkeys(checks_passed)),
                    error_accumulator=list(dict.fromkeys(errors)),
                )
            )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_agent_add_priority_markers_standup_template(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate that the agent added priority markers to the Weekly Standup Template page.
    
    Success criteria:
    1. Gray callout with 📌 icon appears after 'What I plan to do next week' heading but before first todo
    2. All unchecked todos in 'next week' section have 🔥 prefix added
    3. Checked todos remain unchanged
    4. Divider appears after the last todo but before 'Blockers' heading
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    try:
        try:
            # Find Weekly Standup Template page
            standup_pages = _get_pages(backend, "Weekly Standup Template")
        
            if not standup_pages:
                errors.append("[X] Weekly Standup Template page not found")
            else:
                checks_passed.append("[C] Weekly Standup Template page found")
        
            standup_page = standup_pages[0]
            page_id = standup_page.get("_id")
        
            # Get blocks from the page
            blocks = _get_blocks(backend, page_id)
            if not blocks:
                errors.append("[X] Weekly Standup Template page has no content blocks")
            else:
                checks_passed.append("[C] Weekly Standup Template page has content blocks")
        
            # Find key positions
            next_week_heading_index = -1
            blockers_heading_index = -1
            gray_callout_index = -1
            divider_index = -1
            first_todo_after_next_week = -1
            last_todo_before_blockers = -1
        
            has_gray_callout = False
            has_priority_callout_content = False
            has_divider_before_blockers = False
        
            unchecked_todos_with_fire = 0
            total_unchecked_todos_in_section = 0
        
            for i, block in enumerate(blocks):
                block_type = block.get("type", "")
                content = block.get("content", "")
                properties = block.get("properties", {})
            
                # Find 'What I plan to do next week' heading
                if block_type == "heading2" and "plan to do next week" in content.lower():
                    next_week_heading_index = i
            
                # Find 'Blockers' heading
                if block_type == "heading2" and "Blockers" in content:
                    if blockers_heading_index == -1:  # Take the first Blockers heading
                        blockers_heading_index = i
            
                # Find gray callout with 📌 icon
                if block_type == "callout":
                    bg_color = properties.get("backgroundColor", "")
                    icon = properties.get("icon", "")
                    if "gray" in bg_color.lower() and "📌" in icon:
                        has_gray_callout = True
                        gray_callout_index = i
                        if "priority" in content.lower() and "🔥" in content:
                            has_priority_callout_content = True
            
                # Find divider
                if block_type == "divider":
                    divider_index = i
            
                # Check todos in the 'next week' section
                if block_type == "todo" and next_week_heading_index != -1:
                    if blockers_heading_index == -1 or i < blockers_heading_index:
                        # This todo is in the 'next week' section
                        if first_todo_after_next_week == -1:
                            first_todo_after_next_week = i
                        last_todo_before_blockers = i
                    
                        is_checked = properties.get("checked", False)
                        if not is_checked:
                            total_unchecked_todos_in_section += 1
                            if content.startswith("🔥"):
                                unchecked_todos_with_fire += 1
        
            # Validate callout position
            missing = []
        
            if not has_gray_callout:
                missing.append("gray callout with 📌 icon")
            elif not has_priority_callout_content:
                missing.append("callout content about priority items with 🔥")
        
            # Check callout is after heading but before first todo
            if gray_callout_index != -1:
                if next_week_heading_index != -1 and gray_callout_index <= next_week_heading_index:
                    missing.append("callout must appear AFTER 'What I plan to do next week' heading")
                if first_todo_after_next_week != -1 and gray_callout_index >= first_todo_after_next_week:
                    missing.append("callout must appear BEFORE the first todo item")
        
            # Check fire emoji prefix on unchecked todos
            if total_unchecked_todos_in_section > 0:
                if unchecked_todos_with_fire < total_unchecked_todos_in_section:
                    missing.append(f"🔥 prefix on all unchecked todos ({unchecked_todos_with_fire}/{total_unchecked_todos_in_section} have prefix)")
        
            # Check divider position (after last todo, before Blockers)
            if divider_index != -1:
                if last_todo_before_blockers != -1 and divider_index <= last_todo_before_blockers:
                    missing.append("divider must appear AFTER the last todo in section")
                if blockers_heading_index != -1 and divider_index >= blockers_heading_index:
                    missing.append("divider must appear BEFORE 'Blockers' heading")
                has_divider_before_blockers = True
            else:
                missing.append("divider before Blockers heading")
        
            if missing:
                errors.append(f"[X] Priority markers in standup template are missing: {', '.join(missing)}")
            else:
                checks_passed.append(f"[C] Priority markers in standup template are has")
        
            return TaskScore(
                score=1.0 if len(errors) == 0 else 0.0,
                metadata=ScoreMetadata(
                    success_accumulator=list(dict.fromkeys(checks_passed)),
                    error_accumulator=list(dict.fromkeys(errors)),
                )
            )
    
        except Exception as e:
            errors.append(f"[X] Error validating priority markers: {str(e)}")
            return TaskScore(
                score=0.0,
                metadata=ScoreMetadata(
                    success_accumulator=list(dict.fromkeys(checks_passed)),
                    error_accumulator=list(dict.fromkeys(errors)),
                )
            )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_agent_create_code_quality_report(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate that the agent created a Code Quality Report page under Code Examples Repository.
    
    Success criteria:
    1. Page is child of Code Examples Repository
    2. All headings have correct emojis and hierarchy
    3. Callout has purple_background, 📐 icon, and bold target text
    4. Todo blocks have correct checked/unchecked status
    5. Numbered list under Critical Issues has exactly 2 items
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    try:
        try:
            # Find the Code Quality Report page
            report_pages = _get_pages(backend, "Code Quality Report")
        
            if not report_pages:
                errors.append("[X] Code Quality Report page not found")
            else:
                checks_passed.append("[C] Code Quality Report page found")
        
            report_page = report_pages[0]
            page_id = report_page.get("_id")
            parent_id = report_page.get("parentId")
        
            # Verify parent is Code Examples Repository
            code_repo_pages = _get_pages(backend, "Code Examples Repository")
            if not code_repo_pages:
                errors.append("[X] Code Examples Repository page not found")
            else:
                checks_passed.append("[C] Code Examples Repository page found")
        
            code_repo_id = code_repo_pages[0].get("_id")
            if parent_id != code_repo_id:
                errors.append("[X] Code Quality Report is not a child of Code Examples Repository")
            else:
                checks_passed.append("[C] Code Quality Report is a child of Code Examples Repository")
        
            # Get blocks from the page
            blocks = _get_blocks(backend, page_id)
            if not blocks:
                errors.append("[X] Code Quality Report page has no content blocks")
            else:
                checks_passed.append("[C] Code Quality Report page has content blocks")
        
            missing = []
        
            # Check for required headings
            has_h1_quality_analysis = False
            has_h2_repository_overview = False
            has_h2_metrics_summary = False
            has_h3_best_practices = False
            has_h3_warnings = False
            has_h3_critical_issues = False
        
            # Check for other required elements
            has_analysis_paragraph = False
            has_purple_callout = False
            has_callout_bold_text = False
        
            checked_todo_count = 0
            unchecked_todo_count = 0
            numbered_list_count = 0
        
            # Track section positions
            best_practices_index = -1
            warnings_index = -1
            critical_issues_index = -1
        
            for i, block in enumerate(blocks):
                block_type = block.get("type", "")
                content = block.get("content", "")
                properties = block.get("properties", {})
            
                # Check headings
                if block_type == "heading1" and "📊" in content and "Code Quality" in content:
                    has_h1_quality_analysis = True
            
                if block_type == "heading2" and "🔍" in content and "Repository Overview" in content:
                    has_h2_repository_overview = True
            
                if block_type == "heading2" and "📈" in content and "Metrics Summary" in content:
                    has_h2_metrics_summary = True
            
                if block_type == "heading3" and "✅" in content and "Best Practices" in content:
                    has_h3_best_practices = True
                    best_practices_index = i
            
                if block_type == "heading3" and "⚠️" in content and "Warnings" in content:
                    has_h3_warnings = True
                    warnings_index = i
            
                if block_type == "heading3" and "❌" in content and "Critical Issues" in content:
                    has_h3_critical_issues = True
                    critical_issues_index = i
            
                # Check analysis paragraph
                if block_type == "paragraph" and "analysis" in content.lower():
                    has_analysis_paragraph = True
            
                # Check callout
                if block_type == "callout":
                    bg_color = properties.get("backgroundColor", "")
                    icon = properties.get("icon", "")
                    if "purple" in bg_color.lower() and "📐" in icon:
                        has_purple_callout = True
                        if "90%" in content and "coverage" in content.lower():
                            if properties.get("bold", False) or "Target" in content:
                                has_callout_bold_text = True
            
                # Count todos in Best Practices section (should be checked)
                if block_type == "todo" and best_practices_index != -1:
                    if warnings_index == -1 or i < warnings_index:
                        if properties.get("checked", False):
                            checked_todo_count += 1
            
                # Count todos in Warnings section (should be unchecked)
                if block_type == "todo" and warnings_index != -1:
                    if critical_issues_index == -1 or i < critical_issues_index:
                        if i > warnings_index:
                            if not properties.get("checked", False):
                                unchecked_todo_count += 1
            
                # Count numbered list items under Critical Issues
                if block_type == "numberedList" and critical_issues_index != -1:
                    if i > critical_issues_index:
                        numbered_list_count += 1
        
            # Validate headings
            if not has_h1_quality_analysis:
                missing.append("heading_1 '📊 Code Quality Analysis'")
            if not has_h2_repository_overview:
                missing.append("heading_2 '🔍 Repository Overview'")
            if not has_h2_metrics_summary:
                missing.append("heading_2 '📈 Metrics Summary'")
            if not has_h3_best_practices:
                missing.append("heading_3 '✅ Best Practices'")
            if not has_h3_warnings:
                missing.append("heading_3 '⚠️ Warnings'")
            if not has_h3_critical_issues:
                missing.append("heading_3 '❌ Critical Issues'")
        
            # Validate other elements
            if not has_analysis_paragraph:
                missing.append("paragraph with analysis date")
            if not has_purple_callout:
                missing.append("callout with purple_background and 📐 icon")
            if not has_callout_bold_text:
                missing.append("callout with bold target text about code coverage")
        
            # Validate todo counts
            if checked_todo_count < 3:
                missing.append(f"3 checked todos in Best Practices (found {checked_todo_count})")
            if unchecked_todo_count < 2:
                missing.append(f"2 unchecked todos in Warnings (found {unchecked_todo_count})")
        
            # Validate numbered list
            if numbered_list_count != 2:
                missing.append(f"exactly 2 numbered list items under Critical Issues (found {numbered_list_count})")
        
            if missing:
                errors.append(f"[X] Code Quality Report is missing: {', '.join(missing)}")
            else:
                checks_passed.append(f"[C] Code Quality Report is has")
        
            return TaskScore(
                score=1.0 if len(errors) == 0 else 0.0,
                metadata=ScoreMetadata(
                    success_accumulator=list(dict.fromkeys(checks_passed)),
                    error_accumulator=list(dict.fromkeys(errors)),
                )
            )
    
        except Exception as e:
            errors.append(f"[X] Error validating Code Quality Report: {str(e)}")
            return TaskScore(
                score=0.0,
                metadata=ScoreMetadata(
                    success_accumulator=list(dict.fromkeys(checks_passed)),
                    error_accumulator=list(dict.fromkeys(errors)),
                )
            )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_agent_organize_feature_requests_dashboard(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate that the agent organized the Feature Requests page with a summary dashboard.
    
    Success criteria:
    1. Summary dashboard appears at beginning with accurate counts in gray callout
    2. Each unchecked todo has a numbered list item below it with status text
    3. All original content is grouped under 'All Feature Requests' heading
    4. Bookmark with exact URL and caption appears after divider at end
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    try:
        try:
            # Find the Feature Requests page
            feature_pages = _get_pages(backend, "Feature Requests")
        
            if not feature_pages:
                errors.append("[X] Feature Requests page not found")
            else:
                checks_passed.append("[C] Feature Requests page found")
        
            page_id = feature_pages[0].get("_id")
            blocks = _get_blocks(backend, page_id)
        
            if not blocks:
                errors.append("[X] Feature Requests page has no content blocks")
            else:
                checks_passed.append("[C] Feature Requests page has content blocks")
        
            missing = []
        
            # Track key elements
            has_summary_dashboard_heading = False
            has_gray_callout_with_counts = False
            has_all_requests_heading = False
            has_divider_at_end = False
            has_bookmark = False
        
            summary_dashboard_index = -1
            all_requests_heading_index = -1
            divider_index = -1
            bookmark_index = -1
        
            # Count todos for validation
            total_todos = 0
            checked_todos = 0
            unchecked_todos = 0
            status_items_after_unchecked = 0
        
            # First pass: count todos and find key elements
            for i, block in enumerate(blocks):
                block_type = block.get("type", "")
                content = block.get("content", "")
                properties = block.get("properties", {})
            
                if block_type == "heading2":
                    if "📊" in content and "Summary Dashboard" in content:
                        has_summary_dashboard_heading = True
                        summary_dashboard_index = i
                    if "📝" in content and "All Feature Requests" in content:
                        has_all_requests_heading = True
                        all_requests_heading_index = i
            
                if block_type == "callout":
                    bg_color = properties.get("backgroundColor", "")
                    icon = properties.get("icon", "")
                    if "gray" in bg_color.lower() and "📈" in icon:
                        if "Total requests:" in content and "Pending review:" in content and "Approved:" in content:
                            has_gray_callout_with_counts = True
            
                if block_type == "todo":
                    total_todos += 1
                    if properties.get("checked", False):
                        checked_todos += 1
                    else:
                        unchecked_todos += 1
            
                if block_type == "numberedList":
                    if "→ Status: Pending review" in content:
                        status_items_after_unchecked += 1
            
                if block_type == "divider":
                    divider_index = i
            
                if block_type == "bookmark":
                    bookmark_index = i
                    url = properties.get("url", "")
                    caption = properties.get("caption", "")
                    if "feedback.uservoice.com" in url or "feedback.uservoice.com" in content:
                        if "Submit new feature request" in caption or "Submit new feature request" in content:
                            has_bookmark = True
        
            # Validate structure
            if not has_summary_dashboard_heading:
                missing.append("heading_2 '📊 Request Summary Dashboard' at beginning")
        
            if not has_gray_callout_with_counts:
                missing.append("gray callout with 📈 icon containing Total/Pending/Approved counts")
        
            if not has_all_requests_heading:
                missing.append("heading_2 '📝 All Feature Requests'")
        
            # Validate order: summary dashboard should come before all requests heading
            if summary_dashboard_index != -1 and all_requests_heading_index != -1:
                if summary_dashboard_index >= all_requests_heading_index:
                    missing.append("Summary Dashboard should appear before All Feature Requests heading")
        
            # Validate status items for unchecked todos
            if unchecked_todos > 0 and status_items_after_unchecked < unchecked_todos:
                missing.append(f"status numberedList items for all unchecked todos ({status_items_after_unchecked}/{unchecked_todos} found)")
        
            # Validate divider and bookmark at end
            if divider_index == -1:
                missing.append("divider before bookmark")
        
            if not has_bookmark:
                missing.append("bookmark to feedback.uservoice.com with 'Submit new feature request' caption")
        
            # Validate bookmark comes after divider
            if divider_index != -1 and bookmark_index != -1:
                if bookmark_index <= divider_index:
                    missing.append("bookmark should appear after divider")
        
            if missing:
                errors.append(f"[X] Feature Requests organization is missing: {', '.join(missing)}")
            else:
                checks_passed.append(f"[C] Feature Requests organization is has")
        
            return TaskScore(
                score=1.0 if len(errors) == 0 else 0.0,
                metadata=ScoreMetadata(
                    success_accumulator=list(dict.fromkeys(checks_passed)),
                    error_accumulator=list(dict.fromkeys(errors)),
                )
            )
    
        except Exception as e:
            errors.append(f"[X] Error validating Feature Requests organization: {str(e)}")
            return TaskScore(
                score=0.0,
                metadata=ScoreMetadata(
                    success_accumulator=list(dict.fromkeys(checks_passed)),
                    error_accumulator=list(dict.fromkeys(errors)),
                )
            )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_agent_add_meeting_analytics_dashboard(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate that the agent added Meeting Analytics Dashboard to Meeting Notes page.
    
    Success criteria:
    1. Meeting Analytics Dashboard heading appears after the quote block
    2. Callout has gray_background with no icon, containing meeting statistics text
    3. Action Item Tracking section with exact paragraph and numbered list
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    try:
        try:
            # Find the Meeting Notes page
            meeting_pages = _get_pages(backend, "Meeting Notes")
        
            if not meeting_pages:
                errors.append("[X] Meeting Notes page not found")
            else:
                checks_passed.append("[C] Meeting Notes page found")
        
            page_id = meeting_pages[0].get("_id")
            blocks = _get_blocks(backend, page_id)
        
            if not blocks:
                errors.append("[X] Meeting Notes page has no content blocks")
            else:
                checks_passed.append("[C] Meeting Notes page has content blocks")
        
            missing = []
        
            # Track key elements and their positions
            quote_index = -1
            dashboard_heading_index = -1
            gray_callout_index = -1
            action_tracking_index = -1
            action_paragraph_index = -1
        
            has_dashboard_heading = False
            has_gray_callout = False
            has_statistics_content = False
            has_action_tracking_heading = False
            has_action_paragraph = False
        
            numbered_items = []
        
            for i, block in enumerate(blocks):
                block_type = block.get("type", "")
                content = block.get("content", "")
                properties = block.get("properties", {})
            
                # Find the quote block
                if block_type == "quote" and "Good meetings" in content:
                    quote_index = i
            
                # Find dashboard heading
                if block_type == "heading2" and "📊" in content and "Meeting Analytics Dashboard" in content:
                    has_dashboard_heading = True
                    dashboard_heading_index = i
            
                # Find gray callout with statistics
                if block_type == "callout":
                    bg_color = properties.get("backgroundColor", "")
                    icon = properties.get("icon", "")
                    if "gray" in bg_color.lower():
                        # Check for no icon (empty or not present)
                        if not icon or icon == "":
                            has_gray_callout = True
                            gray_callout_index = i
                            # Check for statistics content
                            if "Meeting Statistics" in content or "Total meeting types" in content:
                                has_statistics_content = True
            
                # Check for heading_3 with Meeting Statistics (if not in callout)
                if block_type == "heading3" and "Meeting Statistics" in content:
                    has_statistics_content = True
            
                # Check for bulleted list items with statistics
                if block_type == "bulletedList":
                    if "Total meeting types tracked" in content or "Frequency:" in content or "Next scheduled meetings" in content:
                        has_statistics_content = True
            
                # Find Action Item Tracking heading
                if block_type == "heading3" and "🎯" in content and "Action Item Tracking" in content:
                    has_action_tracking_heading = True
                    action_tracking_index = i
            
                # Find the action paragraph
                if block_type == "paragraph" and "To track action items across all meetings" in content:
                    has_action_paragraph = True
                    action_paragraph_index = i
            
                # Collect numbered list items
                if block_type == "numberedList":
                    if "Clear owner assignment" in content or "Due date specification" in content or "Success criteria" in content:
                        numbered_items.append(content)
        
            # Validate structure
            if not has_dashboard_heading:
                missing.append("heading_2 '📊 Meeting Analytics Dashboard'")
        
            if quote_index != -1 and dashboard_heading_index != -1:
                if dashboard_heading_index <= quote_index:
                    missing.append("Dashboard heading should appear AFTER the quote block")
        
            if not has_gray_callout:
                missing.append("callout with gray_background and no icon")
        
            if not has_statistics_content:
                missing.append("meeting statistics content (Total meeting types, Frequency, Next scheduled)")
        
            if not has_action_tracking_heading:
                missing.append("heading_3 '🎯 Action Item Tracking'")
        
            if not has_action_paragraph:
                missing.append("paragraph about tracking action items")
        
            # Check numbered list items
            expected_items = ["Clear owner assignment", "Due date specification", "Success criteria"]
            for item in expected_items:
                found = any(item in ni for ni in numbered_items)
                if not found:
                    missing.append(f"numbered list item: '{item}'")
        
            if missing:
                errors.append(f"[X] Meeting Analytics Dashboard is missing: {', '.join(missing)}")
            else:
                checks_passed.append(f"[C] Meeting Analytics Dashboard is has")
        
            return TaskScore(
                score=1.0 if len(errors) == 0 else 0.0,
                metadata=ScoreMetadata(
                    success_accumulator=list(dict.fromkeys(checks_passed)),
                    error_accumulator=list(dict.fromkeys(errors)),
                )
            )
    
        except Exception as e:
            errors.append(f"[X] Error validating Meeting Analytics Dashboard: {str(e)}")
            return TaskScore(
                score=0.0,
                metadata=ScoreMetadata(
                    success_accumulator=list(dict.fromkeys(checks_passed)),
                    error_accumulator=list(dict.fromkeys(errors)),
                )
            )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_agent_create_documentation_health_report(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate that the agent created a Documentation Health Report page.
    
    Success criteria:
    1. Page created as sibling to Project Documentation
    2. Callout colors match heading count thresholds (green >10, yellow 5-10, red <5)
    3. Recommendations section correctly categorizes pages
    4. Actual heading counts and update dates are used
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    try:
        try:
            # Find the Documentation Health Report page
            report_pages = _get_pages(backend, "Documentation Health Report")
        
            if not report_pages:
                errors.append("[X] Documentation Health Report page not found")
            else:
                checks_passed.append("[C] Documentation Health Report page found")
        
            report_page = report_pages[0]
            page_id = report_page.get("_id")
            report_parent_id = report_page.get("parentId")
        
            # Find Project Documentation to verify sibling relationship
            project_doc_pages = _get_pages(backend, "Project Documentation")
            if project_doc_pages:
                project_doc_parent_id = project_doc_pages[0].get("parentId")
                # Both should have the same parent (or both be root level)
                if report_parent_id != project_doc_parent_id:
                    errors.append("[X] Documentation Health Report is not a sibling of Project Documentation")
                else:
                    checks_passed.append("[C] Documentation Health Report is a sibling of Project Documentation")
        
            # Get blocks from the page
            blocks = _get_blocks(backend, page_id)
            if not blocks:
                errors.append("[X] Documentation Health Report page has no content blocks")
            else:
                checks_passed.append("[C] Documentation Health Report page has content blocks")
        
            missing = []
        
            # Check for required headings
            has_h1_report = False
            has_h2_coverage = False
            has_h2_recommendations = False
        
            # Track analyzed pages and their callouts
            analyzed_pages = ["API Documentation", "Engineering Wiki", "Company Handbook", "Onboarding Guide"]
            found_page_sections = 0
            found_callouts = 0
        
            # Check for recommendations numbered list
            has_pages_needing_expansion = False
            has_well_documented = False
            has_recently_updated = False
        
            for block in blocks:
                block_type = block.get("type", "")
                content = block.get("content", "")
                properties = block.get("properties", {})
            
                # Check main headings
                if block_type == "heading1" and "📊" in content and "Documentation Health Report" in content:
                    has_h1_report = True
            
                if block_type == "heading2" and "🔍" in content and "Coverage Analysis" in content:
                    has_h2_coverage = True
            
                if block_type == "heading2" and "📈" in content and "Recommendations" in content:
                    has_h2_recommendations = True
            
                # Check for analyzed page sections (heading_3 with page titles)
                if block_type == "heading3":
                    for page_name in analyzed_pages:
                        if page_name in content:
                            found_page_sections += 1
                            break
            
                # Check for callouts with correct background colors
                if block_type == "callout":
                    bg_color = properties.get("backgroundColor", "")
                    if any(c in bg_color.lower() for c in ["green", "yellow", "red"]):
                        if "sections" in content.lower() or "headings" in content.lower() or "updated" in content.lower():
                            found_callouts += 1
            
                # Check recommendations numbered list items
                if block_type == "numberedList":
                    if "needing expansion" in content.lower() or "need expansion" in content.lower():
                        has_pages_needing_expansion = True
                    if "well-documented" in content.lower() or "well documented" in content.lower():
                        has_well_documented = True
                    if "recently updated" in content.lower():
                        has_recently_updated = True
        
            # Validate structure
            if not has_h1_report:
                missing.append("heading_1 '📊 Documentation Health Report'")
        
            if not has_h2_coverage:
                missing.append("heading_2 '🔍 Coverage Analysis'")
        
            if not has_h2_recommendations:
                missing.append("heading_2 '📈 Recommendations'")
        
            # Check that we have sections for analyzed pages
            if found_page_sections < 4:
                missing.append(f"heading_3 sections for all 4 analyzed pages (found {found_page_sections})")
        
            # Check for colored callouts
            if found_callouts < 4:
                missing.append(f"colored callouts for all analyzed pages (found {found_callouts})")
        
            # Check recommendations items
            if not has_pages_needing_expansion:
                missing.append("numbered list item about pages needing expansion")
            if not has_well_documented:
                missing.append("numbered list item about well-documented pages")
            if not has_recently_updated:
                missing.append("numbered list item about recently updated pages")
        
            if missing:
                errors.append(f"[X] Documentation Health Report is missing: {', '.join(missing)}")
            else:
                checks_passed.append(f"[C] Documentation Health Report is has")
        
            return TaskScore(
                score=1.0 if len(errors) == 0 else 0.0,
                metadata=ScoreMetadata(
                    success_accumulator=list(dict.fromkeys(checks_passed)),
                    error_accumulator=list(dict.fromkeys(errors)),
                )
            )
    
        except Exception as e:
            errors.append(f"[X] Error validating Documentation Health Report: {str(e)}")
            return TaskScore(
                score=0.0,
                metadata=ScoreMetadata(
                    success_accumulator=list(dict.fromkeys(checks_passed)),
                    error_accumulator=list(dict.fromkeys(errors)),
                )
            )

    # -----------------------------------------------------------------------------
    # enhance-sprint-planning-meeting-v2
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_enhance_sprint_planning_meeting(
    backend: Backend, goal: Dict[str, Any]
) -> TaskScore:
    """
    Validates the Sprint Planning - Jan 15 page meeting enhancement.
    
    Requirements:
    1. Blue callout at top (after heading1, before 'Attendees') with:
       - icon 📋
       - blue_background
       - Contains 'Meeting Overview' (bold), date, duration, counts
    2. After each Sprint Goals numbered list item: yellow callout with 'Acceptance Criteria' heading_3 and 2 bulleted items
    3. After each Action Items todo: italic paragraph with 'Assigned on: January 15, 2024 | Due date: TBD'
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    try:
        try:
            # Find Sprint Planning - Jan 15 page
            sprint_pages = _get_pages(backend, "Sprint Planning - Jan 15")
            if not sprint_pages:
                errors.append("[X] Sprint Planning - Jan 15 page not found")
            else:
                checks_passed.append("[C] Sprint Planning - Jan 15 page found")
        
            page = sprint_pages[0]
            page_id = page.get("_id")
            blocks = _get_blocks(backend, page_id)
        
            if not blocks:
                errors.append("[X] Sprint Planning - Jan 15 page has no blocks")
            else:
                checks_passed.append("[C] Sprint Planning - Jan 15 page has blocks")
        
            missing = []
        
            # Track state for validation
            has_blue_overview_callout = False
            blue_callout_has_meeting_overview = False
            blue_callout_has_date = False
            blue_callout_has_duration = False
            blue_callout_has_counts = False
        
            yellow_callouts_after_goals = 0
            acceptance_criteria_count = 0
            bulleted_items_in_criteria = 0
        
            italic_paragraphs_after_todos = 0
        
            # Count expected items
            sprint_goals_items = 0
            action_items_todos = 0
        
            # Track sections
            in_sprint_goals = False
            in_action_items = False
            found_heading1 = False
            found_attendees = False
        
            # First pass: count goals and todos
            for block in blocks:
                content = block.get("content", "")
                block_type = block.get("type", "")
            
                if block_type == "heading2":
                    if "Sprint Goals" in content:
                        in_sprint_goals = True
                        in_action_items = False
                    elif "Action Items" in content:
                        in_sprint_goals = False
                        in_action_items = True
                    else:
                        in_sprint_goals = False
                        in_action_items = False
            
                if in_sprint_goals and block_type == "numberedList":
                    sprint_goals_items += 1
            
                if in_action_items and block_type == "todo":
                    action_items_todos += 1
        
            # Second pass: validate structure
            in_sprint_goals = False
            in_action_items = False
            prev_was_goal_item = False
            prev_was_todo = False
        
            for i, block in enumerate(blocks):
                content = block.get("content", "")
                block_type = block.get("type", "")
                properties = block.get("properties", {})
            
                # Check for heading1 (main title)
                if block_type == "heading1":
                    found_heading1 = True
            
                # Check for Attendees heading (should come after blue callout)
                if block_type == "heading2" and "Attendees" in content:
                    found_attendees = True
            
                # Check for blue overview callout (between heading1 and Attendees)
                if block_type == "callout" and found_heading1 and not found_attendees:
                    bg_color = properties.get("backgroundColor", "")
                    icon = properties.get("icon", "")
                
                    if "blue" in bg_color.lower():
                        has_blue_overview_callout = True
                        if icon == "📋":
                            # Check content for required fields
                            if "Meeting Overview" in content:
                                blue_callout_has_meeting_overview = True
                            if "January 15, 2024" in content or "Date:" in content:
                                blue_callout_has_date = True
                            if "2 weeks" in content or "Sprint Duration" in content:
                                blue_callout_has_duration = True
                            if "Total Goals:" in content or "Total Action Items:" in content:
                                blue_callout_has_counts = True
            
                # Track sections
                if block_type == "heading2":
                    if "Sprint Goals" in content:
                        in_sprint_goals = True
                        in_action_items = False
                    elif "Action Items" in content:
                        in_sprint_goals = False
                        in_action_items = True
                    else:
                        in_sprint_goals = False
                        in_action_items = False
            
                # Check for yellow callouts after sprint goals items
                if in_sprint_goals and prev_was_goal_item:
                    if block_type == "callout":
                        bg_color = properties.get("backgroundColor", "")
                        if "yellow" in bg_color.lower():
                            yellow_callouts_after_goals += 1
            
                # Check for heading3 'Acceptance Criteria'
                if block_type == "heading3" and "Acceptance Criteria" in content:
                    acceptance_criteria_count += 1
            
                # Check for bulleted list items with criteria content
                if block_type == "bulletedList":
                    if "Definition of done" in content or "Success metrics" in content:
                        bulleted_items_in_criteria += 1
            
                # Check for italic paragraphs after todos
                if in_action_items and prev_was_todo:
                    if block_type == "paragraph":
                        is_italic = properties.get("italic", False)
                        if is_italic and "Assigned on:" in content and "Due date:" in content:
                            italic_paragraphs_after_todos += 1
            
                # Track previous block type
                prev_was_goal_item = in_sprint_goals and block_type == "numberedList"
                prev_was_todo = in_action_items and block_type == "todo"
        
            # Validate blue overview callout
            if not has_blue_overview_callout:
                missing.append("blue callout with 📋 icon at top of page")
            else:
                if not blue_callout_has_meeting_overview:
                    missing.append("'Meeting Overview' in blue callout")
                if not blue_callout_has_date:
                    missing.append("date field in blue callout")
                if not blue_callout_has_duration:
                    missing.append("sprint duration in blue callout")
                if not blue_callout_has_counts:
                    missing.append("goal/action item counts in blue callout")
        
            # Validate yellow callouts and acceptance criteria structure
            # Note: Due to nested block limitations, we check for the presence but may be more lenient
            if yellow_callouts_after_goals < sprint_goals_items:
                missing.append(f"yellow callouts after each sprint goal (found {yellow_callouts_after_goals}, expected {sprint_goals_items})")
        
            if acceptance_criteria_count < sprint_goals_items:
                missing.append(f"'Acceptance Criteria' headings (found {acceptance_criteria_count}, expected {sprint_goals_items})")
        
            expected_bulleted = sprint_goals_items * 2
            if bulleted_items_in_criteria < expected_bulleted:
                missing.append(f"bulleted criteria items (found {bulleted_items_in_criteria}, expected {expected_bulleted})")
        
            # Validate italic paragraphs after todos
            if italic_paragraphs_after_todos < action_items_todos:
                missing.append(f"italic 'Assigned on' paragraphs after todos (found {italic_paragraphs_after_todos}, expected {action_items_todos})")
        
            if missing:
                errors.append(f"[X] Sprint Planning meeting enhancement missing: {', '.join(missing)}")
            else:
                checks_passed.append(f"[C] Sprint Planning meeting enhancement has")
        
            return TaskScore(
                score=1.0 if len(errors) == 0 else 0.0,
                metadata=ScoreMetadata(
                    success_accumulator=list(dict.fromkeys(checks_passed)),
                    error_accumulator=list(dict.fromkeys(errors)),
                )
            )
    
        except Exception as e:
            errors.append(f"[X] Error validating Sprint Planning meeting enhancement: {str(e)}")
            return TaskScore(
                score=0.0,
                metadata=ScoreMetadata(
                    success_accumulator=list(dict.fromkeys(checks_passed)),
                    error_accumulator=list(dict.fromkeys(errors)),
                )
            )

    # -----------------------------------------------------------------------------
    # add-prd-executive-summary-v2
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_add_prd_executive_summary(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validates the PRD Executive Summary addition.
    
    Requirements:
    1. New subsection 'Overview - Executive Summary' appears after all Part 3 content
    2. Green callout with ✅ icon containing 'Key Requirements Met: 12/15 (80%)'
    3. Paragraph with calculated section (heading_2) and bullet (bulletedList) counts
    4. Bookmark with url 'https://requirements.docs.com/latest' and caption
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    try:
        try:
            # Find Product Requirements Document page
            prd_pages = _get_pages(backend, "Comprehensive Product Requirements Document")
            if not prd_pages:
                errors.append("[X] Comprehensive Product Requirements Document page not found")
            else:
                checks_passed.append("[C] Comprehensive Product Requirements Document page found")
        
            page = prd_pages[0]
            page_id = page.get("_id")
            blocks = _get_blocks(backend, page_id)
        
            if not blocks:
                errors.append("[X] Product Requirements Document page has no blocks")
            else:
                checks_passed.append("[C] Product Requirements Document page has blocks")
        
            missing = []
        
            # Count heading_2 and bulletedList blocks for validation
            heading2_count = 0
            bulleted_count = 0
        
            for block in blocks:
                block_type = block.get("type", "")
                if block_type == "heading2":
                    heading2_count += 1
                if block_type == "bulletedList":
                    bulleted_count += 1
        
            # Track validation state
            has_executive_summary_heading = False
            has_green_callout = False
            has_requirements_text = False
            has_paragraph_with_counts = False
            has_bookmark = False
            bookmark_has_correct_url = False
            bookmark_has_caption = False
        
            # Find Overview - Part 3 position and verify Executive Summary comes after
            part3_index = -1
            executive_summary_index = -1
        
            for i, block in enumerate(blocks):
                content = block.get("content", "")
                block_type = block.get("type", "")
                properties = block.get("properties", {})
            
                # Track Part 3 location
                if block_type == "heading3" and "Overview - Part 3" in content:
                    part3_index = i
            
                # Check for Executive Summary heading
                if block_type == "heading3" and "Overview - Executive Summary" in content:
                    has_executive_summary_heading = True
                    executive_summary_index = i
            
                # Check for green callout with requirements text
                if block_type == "callout":
                    bg_color = properties.get("backgroundColor", "")
                    icon = properties.get("icon", "")
                
                    if "green" in bg_color.lower():
                        has_green_callout = True
                        if icon == "✅":
                            if "Key Requirements Met" in content and "12/15" in content and "80%" in content:
                                has_requirements_text = True
            
                # Check for paragraph with counts
                if block_type == "paragraph":
                    if "main sections" in content.lower() and "requirement points" in content.lower():
                        # Verify counts are present (X and Y should be numbers)
                        has_paragraph_with_counts = True
            
                # Check for bookmark
                if block_type == "bookmark":
                    has_bookmark = True
                    url = properties.get("url", "")
                    caption = properties.get("caption", "")
                
                    if url == "https://requirements.docs.com/latest":
                        bookmark_has_correct_url = True
                    if caption and "requirements" in caption.lower():
                        bookmark_has_caption = True
        
            # Validate positioning - Executive Summary should come after Part 3
            if part3_index >= 0 and executive_summary_index >= 0:
                if executive_summary_index <= part3_index:
                    missing.append("'Overview - Executive Summary' should appear AFTER 'Overview - Part 3'")
        
            # Validate all required elements
            if not has_executive_summary_heading:
                missing.append("heading_3 'Overview - Executive Summary'")
        
            if not has_green_callout:
                missing.append("callout with green_background")
            elif not has_requirements_text:
                missing.append("callout with exact text 'Key Requirements Met: 12/15 (80%)'")
        
            if not has_paragraph_with_counts:
                missing.append("paragraph with section and bullet counts")
        
            if not has_bookmark:
                missing.append("bookmark block")
            else:
                if not bookmark_has_correct_url:
                    missing.append("bookmark with url 'https://requirements.docs.com/latest'")
                if not bookmark_has_caption:
                    missing.append("bookmark with caption about requirements updates")
        
            if missing:
                errors.append(f"[X] PRD Executive Summary is missing: {', '.join(missing)}")
            else:
                checks_passed.append(f"[C] PRD Executive Summary is has")
        
            return TaskScore(
                score=1.0 if len(errors) == 0 else 0.0,
                metadata=ScoreMetadata(
                    success_accumulator=list(dict.fromkeys(checks_passed)),
                    error_accumulator=list(dict.fromkeys(errors)),
                )
            )
    
        except Exception as e:
            errors.append(f"[X] Error validating PRD Executive Summary: {str(e)}")
            return TaskScore(
                score=0.0,
                metadata=ScoreMetadata(
                    success_accumulator=list(dict.fromkeys(checks_passed)),
                    error_accumulator=list(dict.fromkeys(errors)),
                )
            )

    # -----------------------------------------------------------------------------
    # add-sprint-metrics-section-2-v2
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_add_sprint_metrics_section_2(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validates the Sprint Metrics section addition to Sprint Planning - Jan 15 page.
    
    Requirements:
    1. New '📊 Sprint Metrics' heading_2 appears after 'Action Items' section
    2. Code block with language 'markdown' contains exact metrics text
    3. Yellow callout with ⚡ icon contains performance note
    4. Duplicated Attendees section at end with heading '📝 Meeting Participants'
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    try:
        try:
            # Find Sprint Planning - Jan 15 page
            sprint_pages = _get_pages(backend, "Sprint Planning - Jan 15")
            if not sprint_pages:
                errors.append("[X] Sprint Planning - Jan 15 page not found")
            else:
                checks_passed.append("[C] Sprint Planning - Jan 15 page found")
        
            page = sprint_pages[0]
            page_id = page.get("_id")
            blocks = _get_blocks(backend, page_id)
        
            if not blocks:
                errors.append("[X] Sprint Planning - Jan 15 page has no blocks")
            else:
                checks_passed.append("[C] Sprint Planning - Jan 15 page has blocks")
        
            missing = []
        
            # Track validation state
            has_sprint_metrics_heading = False
            has_code_block = False
            code_block_has_markdown_lang = False
            code_block_has_metrics = False
            has_yellow_callout = False
            callout_has_lightning_icon = False
            callout_has_performance_text = False
            has_meeting_participants_heading = False
            has_duplicated_attendees = False
        
            # Track positions
            action_items_index = -1
            sprint_metrics_index = -1
            meeting_participants_index = -1
        
            # Count attendee bullets for verification
            original_attendee_bullets = []
            duplicated_attendee_bullets = []
            in_original_attendees = False
            in_duplicated_participants = False
        
            for i, block in enumerate(blocks):
                block_type = block.get("type", "")
                content = block.get("content", "")
                properties = block.get("properties", {})
            
                # Track Action Items heading
                if block_type == "heading2" and "Action Items" in content:
                    action_items_index = i
                    in_original_attendees = False
            
                # Track original Attendees section
                if block_type == "heading2" and "Attendees" in content and "Meeting Participants" not in content:
                    in_original_attendees = True
                    in_duplicated_participants = False
            
                # Collect original attendee bullets
                if in_original_attendees and block_type == "bulletedList":
                    original_attendee_bullets.append(content)
            
                # Check for Sprint Metrics heading
                if block_type == "heading2" and "📊" in content and "Sprint Metrics" in content:
                    has_sprint_metrics_heading = True
                    sprint_metrics_index = i
                    in_original_attendees = False
            
                # Check for code block with markdown language
                if block_type == "code":
                    has_code_block = True
                    lang = properties.get("language", "")
                    if lang.lower() == "markdown":
                        code_block_has_markdown_lang = True
                    # Check for metrics content
                    if "Sprint Velocity" in content and "Story Points" in content:
                        code_block_has_metrics = True
            
                # Check for yellow callout with lightning icon
                if block_type == "callout":
                    bg_color = properties.get("backgroundColor", "")
                    icon = properties.get("icon", "")
                
                    if "yellow" in bg_color.lower():
                        has_yellow_callout = True
                        if icon == "⚡":
                            callout_has_lightning_icon = True
                        if "velocity improved" in content.lower() or "12%" in content:
                            callout_has_performance_text = True
            
                # Check for Meeting Participants heading (duplicated Attendees)
                if block_type == "heading2" and "📝" in content and "Meeting Participants" in content:
                    has_meeting_participants_heading = True
                    meeting_participants_index = i
                    in_duplicated_participants = True
                    in_original_attendees = False
            
                # Collect duplicated attendee bullets
                if in_duplicated_participants and block_type == "bulletedList":
                    duplicated_attendee_bullets.append(content)
        
            # Validate Sprint Metrics position (should be after Action Items)
            if action_items_index >= 0 and sprint_metrics_index >= 0:
                if sprint_metrics_index <= action_items_index:
                    missing.append("'📊 Sprint Metrics' should appear AFTER 'Action Items'")
        
            # Validate Meeting Participants is at end (after Sprint Metrics)
            if sprint_metrics_index >= 0 and meeting_participants_index >= 0:
                if meeting_participants_index <= sprint_metrics_index:
                    missing.append("'📝 Meeting Participants' should appear AFTER 'Sprint Metrics'")
        
            # Validate all required elements
            if not has_sprint_metrics_heading:
                missing.append("heading_2 '📊 Sprint Metrics'")
        
            if not has_code_block:
                missing.append("code block")
            elif not code_block_has_markdown_lang:
                missing.append("code block with language 'markdown'")
            elif not code_block_has_metrics:
                missing.append("code block with Sprint Velocity metrics content")
        
            if not has_yellow_callout:
                missing.append("callout with yellow_background")
            else:
                if not callout_has_lightning_icon:
                    missing.append("callout with ⚡ icon")
                if not callout_has_performance_text:
                    missing.append("callout with performance improvement text")
        
            if not has_meeting_participants_heading:
                missing.append("heading_2 '📝 Meeting Participants' (duplicated Attendees)")
        
            # Check that attendee content was duplicated
            if len(duplicated_attendee_bullets) == 0 and len(original_attendee_bullets) > 0:
                missing.append("duplicated attendee bullet points under Meeting Participants")
            elif len(duplicated_attendee_bullets) > 0:
                # Verify content matches
                for bullet in original_attendee_bullets:
                    if bullet not in duplicated_attendee_bullets:
                        missing.append(f"duplicated attendee: '{bullet}'")
                        break
        
            if missing:
                errors.append(f"[X] Sprint Metrics section is missing: {', '.join(missing)}")
            else:
                checks_passed.append(f"[C] Sprint Metrics section is has")
        
            return TaskScore(
                score=1.0 if len(errors) == 0 else 0.0,
                metadata=ScoreMetadata(
                    success_accumulator=list(dict.fromkeys(checks_passed)),
                    error_accumulator=list(dict.fromkeys(errors)),
                )
            )
    
        except Exception as e:
            errors.append(f"[X] Error validating Sprint Metrics section: {str(e)}")
            return TaskScore(
                score=0.0,
                metadata=ScoreMetadata(
                    success_accumulator=list(dict.fromkeys(checks_passed)),
                    error_accumulator=list(dict.fromkeys(errors)),
                )
            )

    # -----------------------------------------------------------------------------
    # reorganize-company-handbook-3-v2
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_reorganize_company_handbook_3(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validates the Company Handbook reorganization.
    
    Requirements:
    1. 'Work Policies' section now appears before 'Our Values' section
    2. 'Quick Reference' section appears between title and 'Work Policies'
    3. Callout with blue_background, 📌 icon, and today's date
    4. Three unchecked to-do blocks with exact text
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    try:
        try:
            # Find Company Handbook page
            handbook_pages = _get_pages(backend, "Company Handbook")
            if not handbook_pages:
                errors.append("[X] Company Handbook page not found")
            else:
                checks_passed.append("[C] Company Handbook page found")
        
            page = handbook_pages[0]
            page_id = page.get("_id")
            blocks = _get_blocks(backend, page_id)
        
            if not blocks:
                errors.append("[X] Company Handbook page has no blocks")
            else:
                checks_passed.append("[C] Company Handbook page has blocks")
        
            missing = []
        
            # Track positions of sections
            title_index = -1
            quick_reference_index = -1
            work_policies_index = -1
            our_values_index = -1
        
            # Track validation state
            has_quick_reference = False
            has_blue_callout = False
            callout_has_pin_icon = False
            callout_has_date = False
        
            # Track to-do blocks
            expected_todos = [
                "Review company values quarterly",
                "Update remote work policy annually",
                "Verify benefits information is current"
            ]
            found_todos = []
        
            for i, block in enumerate(blocks):
                block_type = block.get("type", "")
                content = block.get("content", "")
                properties = block.get("properties", {})
            
                # Track main title
                if block_type == "heading1":
                    title_index = i
            
                # Track Quick Reference section
                if block_type == "heading2" and "📋" in content and "Quick Reference" in content:
                    has_quick_reference = True
                    quick_reference_index = i
            
                # Track Work Policies section
                if block_type == "heading2" and "Work Policies" in content and "Quick Reference" not in content:
                    work_policies_index = i
            
                # Track Our Values section
                if block_type == "heading2" and "Our Values" in content:
                    our_values_index = i
            
                # Check for blue callout with pin icon
                if block_type == "callout":
                    bg_color = properties.get("backgroundColor", "")
                    icon = properties.get("icon", "")
                
                    if "blue" in bg_color.lower():
                        has_blue_callout = True
                        if icon == "📌":
                            callout_has_pin_icon = True
                        # Check for date mention (various formats)
                        if "reviewed" in content.lower() or "date" in content.lower() or "2024" in content or "2025" in content or "2026" in content:
                            callout_has_date = True
            
                # Check for to-do blocks
                if block_type == "todo":
                    checked = properties.get("checked", False)
                    if not checked:
                        for expected in expected_todos:
                            if expected in content or expected.replace("☐ ", "") in content:
                                found_todos.append(expected)
                                break
        
            # Validate section ordering
            if quick_reference_index >= 0 and work_policies_index >= 0:
                if quick_reference_index >= work_policies_index:
                    missing.append("'Quick Reference' should appear BEFORE 'Work Policies'")
        
            if work_policies_index >= 0 and our_values_index >= 0:
                if work_policies_index >= our_values_index:
                    missing.append("'Work Policies' should appear BEFORE 'Our Values' (sections swapped)")
        
            if title_index >= 0 and quick_reference_index >= 0:
                if quick_reference_index <= title_index:
                    missing.append("'Quick Reference' should appear AFTER the title")
        
            # Validate required elements
            if not has_quick_reference:
                missing.append("heading_2 '📋 Quick Reference'")
        
            if not has_blue_callout:
                missing.append("callout with blue_background")
            else:
                if not callout_has_pin_icon:
                    missing.append("callout with 📌 icon")
                if not callout_has_date:
                    missing.append("callout with date reference")
        
            # Validate to-do blocks
            for expected in expected_todos:
                short_version = expected.replace("☐ ", "")
                if expected not in found_todos and short_version not in found_todos:
                    missing.append(f"unchecked todo: '{short_version}'")
        
            if missing:
                errors.append(f"[X] Company Handbook reorganization is missing: {', '.join(missing)}")
            else:
                checks_passed.append(f"[C] Company Handbook reorganization is has")
        
            return TaskScore(
                score=1.0 if len(errors) == 0 else 0.0,
                metadata=ScoreMetadata(
                    success_accumulator=list(dict.fromkeys(checks_passed)),
                    error_accumulator=list(dict.fromkeys(errors)),
                )
            )
    
        except Exception as e:
            errors.append(f"[X] Error validating Company Handbook reorganization: {str(e)}")
            return TaskScore(
                score=0.0,
                metadata=ScoreMetadata(
                    success_accumulator=list(dict.fromkeys(checks_passed)),
                    error_accumulator=list(dict.fromkeys(errors)),
                )
            )

    # -----------------------------------------------------------------------------
    # create-meeting-archive-system-v2
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_create_meeting_archive_system(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validates the Meeting Archive System creation.
    
    Requirements:
    1. 'Archived Meetings 2024' page exists with 📁 icon
    2. Both meeting pages are children of the archive page
    3. Meeting Activity Summary section added after quarterly meetings list
    4. Numbered list shows archived meetings with icons
    5. Callout with brown background, ⚠️ icon, and specific text
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    try:
        try:
            # Find Meeting Notes page
            meeting_notes_pages = _get_pages(backend, "Meeting Notes")
            if not meeting_notes_pages:
                errors.append("[X] Meeting Notes page not found")
            else:
                checks_passed.append("[C] Meeting Notes page found")
        
            meeting_notes = meeting_notes_pages[0]
            meeting_notes_id = meeting_notes.get("_id")
        
            # Find Archived Meetings 2024 page
            archive_pages = _get_pages(backend, "Archived Meetings 2024")
            if not archive_pages:
                errors.append("[X] Archived Meetings 2024 page not found")
            else:
                checks_passed.append("[C] Archived Meetings 2024 page found")
        
            archive_page = archive_pages[0]
            archive_page_id = archive_page.get("_id")
            archive_icon = archive_page.get("icon", "")
        
            missing = []
        
            # Check archive page icon
            if archive_icon != "📁":
                missing.append(f"archive page should have 📁 icon (found: '{archive_icon}')")
        
            # Check archive page is child of Meeting Notes
            archive_parent = archive_page.get("parentId", "")
            if archive_parent != meeting_notes_id:
                missing.append("Archived Meetings 2024 should be a child of Meeting Notes")
        
            # Find Sprint Planning and Team Retrospective pages
            sprint_pages = _get_pages(backend, "Sprint Planning - Jan 15")
            retro_pages = _get_pages(backend, "Team Retrospective")
        
            if not sprint_pages:
                missing.append("Sprint Planning - Jan 15 page not found")
            else:
                sprint_parent = sprint_pages[0].get("parentId", "")
                if sprint_parent != archive_page_id:
                    missing.append("Sprint Planning - Jan 15 should be a child of Archived Meetings 2024")
        
            if not retro_pages:
                missing.append("Team Retrospective page not found")
            else:
                retro_parent = retro_pages[0].get("parentId", "")
                if retro_parent != archive_page_id:
                    missing.append("Team Retrospective should be a child of Archived Meetings 2024")
        
            # Check Meeting Notes content
            blocks = _get_blocks(backend, meeting_notes_id)
        
            if not blocks:
                missing.append("Meeting Notes page has no blocks")
            else:
                # Track validation state
                has_activity_summary = False
                has_numbered_list = False
                has_brown_callout = False
                callout_has_warning_icon = False
                callout_has_archive_text = False
            
                for block in blocks:
                    block_type = block.get("type", "")
                    content = block.get("content", "")
                    properties = block.get("properties", {})
                
                    # Check for Meeting Activity Summary heading
                    if block_type == "heading2" and "📊" in content and "Meeting Activity Summary" in content:
                        has_activity_summary = True
                
                    # Check for numbered list with archived meetings
                    if block_type == "numberedList":
                        if "Archived" in content or "archived" in content:
                            has_numbered_list = True
                
                    # Check for callout
                    if block_type == "callout":
                        bg_color = properties.get("backgroundColor", "")
                        icon = properties.get("icon", "")
                    
                        if "brown" in bg_color.lower():
                            has_brown_callout = True
                            if icon == "⚠️":
                                callout_has_warning_icon = True
                            if "archived" in content.lower() and "2024" in content:
                                callout_has_archive_text = True
            
                if not has_activity_summary:
                    missing.append("heading_2 '📊 Meeting Activity Summary'")
            
                if not has_numbered_list:
                    missing.append("numbered list with archived meetings")
            
                if not has_brown_callout:
                    missing.append("callout with brown_background")
                else:
                    if not callout_has_warning_icon:
                        missing.append("callout with ⚠️ icon")
                    if not callout_has_archive_text:
                        missing.append("callout with archive text mentioning 2024")
        
            if missing:
                errors.append(f"[X] Meeting Archive System is missing: {', '.join(missing)}")
            else:
                checks_passed.append(f"[C] Meeting Archive System is has")
        
            return TaskScore(
                score=1.0 if len(errors) == 0 else 0.0,
                metadata=ScoreMetadata(
                    success_accumulator=list(dict.fromkeys(checks_passed)),
                    error_accumulator=list(dict.fromkeys(errors)),
                )
            )
    
        except Exception as e:
            errors.append(f"[X] Error validating Meeting Archive System: {str(e)}")
            return TaskScore(
                score=0.0,
                metadata=ScoreMetadata(
                    success_accumulator=list(dict.fromkeys(checks_passed)),
                    error_accumulator=list(dict.fromkeys(errors)),
                )
            )

    # -----------------------------------------------------------------------------
    # create-retrospective-analysis-v2
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_create_retrospective_analysis(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validates the Sprint Retrospective Analysis page creation.
    
    Requirements:
    1. Page exists as child of Team Retrospective
    2. Numbered list contains all bullet items from parent
    3. Todos transform bullets into 'Address:' format
    4. Orange callout with lightbulb shows correct counts
    5. Metrics paragraph shows positive vs improvement counts
    6. Follow-up todo at end
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    try:
        try:
            # Find Team Retrospective page
            retro_pages = _get_pages(backend, "Team Retrospective")
            if not retro_pages:
                errors.append("[X] Team Retrospective page not found")
            else:
                checks_passed.append("[C] Team Retrospective page found")
        
            retro_page = retro_pages[0]
            retro_page_id = retro_page.get("_id")
        
            # Get parent page blocks to count bullets
            parent_blocks = _get_blocks(backend, retro_page_id)
            parent_bullets = []
            for block in parent_blocks:
                if block.get("type") == "bulletedList":
                    parent_bullets.append(block.get("content", ""))
        
            # Find Sprint Retrospective Analysis page
            analysis_pages = _get_pages(backend, "Sprint Retrospective Analysis")
            if not analysis_pages:
                errors.append("[X] Sprint Retrospective Analysis page not found")
            else:
                checks_passed.append("[C] Sprint Retrospective Analysis page found")
        
            analysis_page = analysis_pages[0]
            analysis_page_id = analysis_page.get("_id")
            analysis_parent = analysis_page.get("parentId", "")
        
            missing = []
        
            # Check parent relationship
            if analysis_parent != retro_page_id:
                missing.append("page should be a child of Team Retrospective")
        
            # Get analysis page blocks
            blocks = _get_blocks(backend, analysis_page_id)
        
            if not blocks:
                missing.append("analysis page has no blocks")
            else:
                # Track validation state
                has_deep_dive_heading = False
                has_feedback_heading = False
                has_action_items_heading = False
                has_metrics_heading = False
                has_followup_heading = False
                has_orange_callout = False
                callout_has_lightbulb = False
                callout_has_counts = False
                has_metrics_paragraph = False
                has_followup_todo = False
            
                # Track bullets and todos
                numbered_items = []
                address_todos = []
            
                for block in blocks:
                    block_type = block.get("type", "")
                    content = block.get("content", "")
                    properties = block.get("properties", {})
                
                    # Check headings
                    if block_type == "heading1" and "🔄" in content and "Sprint Retrospective" in content:
                        has_deep_dive_heading = True
                
                    if block_type == "heading2" and "📊" in content and "Original Feedback" in content:
                        has_feedback_heading = True
                
                    if block_type == "heading2" and "🎯" in content and "Action Items" in content:
                        has_action_items_heading = True
                
                    if block_type == "heading2" and "📈" in content and "Retrospective Metrics" in content:
                        has_metrics_heading = True
                
                    if block_type == "heading3" and "🗓️" in content and "Follow-up" in content:
                        has_followup_heading = True
                
                    # Check numbered list
                    if block_type == "numberedList":
                        numbered_items.append(content)
                
                    # Check todos
                    if block_type == "todo":
                        if "Address:" in content:
                            address_todos.append(content)
                        if "Review action items" in content or "next retrospective" in content:
                            has_followup_todo = True
                
                    # Check callout
                    if block_type == "callout":
                        bg_color = properties.get("backgroundColor", "")
                        icon = properties.get("icon", "")
                    
                        if "orange" in bg_color.lower():
                            has_orange_callout = True
                            if icon == "💡":
                                callout_has_lightbulb = True
                            if "Insight:" in content and "identified" in content and "created" in content:
                                callout_has_counts = True
                
                    # Check metrics paragraph
                    if block_type == "paragraph":
                        if "Positive items:" in content and "Improvement areas:" in content:
                            has_metrics_paragraph = True
            
                # Validate headings
                if not has_deep_dive_heading:
                    missing.append("heading_1 '🔄 Sprint Retrospective Deep Dive'")
                if not has_feedback_heading:
                    missing.append("heading_2 '📊 Original Feedback Analysis'")
                if not has_action_items_heading:
                    missing.append("heading_2 '🎯 Action Items Generated'")
                if not has_metrics_heading:
                    missing.append("heading_2 '📈 Retrospective Metrics'")
                if not has_followup_heading:
                    missing.append("heading_3 '🗓️ Follow-up Schedule'")
            
                # Validate callout
                if not has_orange_callout:
                    missing.append("callout with orange_background")
                else:
                    if not callout_has_lightbulb:
                        missing.append("callout with 💡 icon")
                    if not callout_has_counts:
                        missing.append("callout with counts in 'Insight:' format")
            
                # Validate numbered list (should have parent's bullet items)
                if len(parent_bullets) > 0 and len(numbered_items) < len(parent_bullets):
                    missing.append(f"numbered list should have all {len(parent_bullets)} bullet items from parent")
            
                # Validate address todos
                if len(parent_bullets) > 0 and len(address_todos) < len(parent_bullets):
                    missing.append(f"should have {len(parent_bullets)} 'Address:' todos for each bullet")
            
                # Validate metrics paragraph
                if not has_metrics_paragraph:
                    missing.append("paragraph with 'Positive items:' and 'Improvement areas:' counts")
            
                # Validate follow-up todo
                if not has_followup_todo:
                    missing.append("todo '📅 Review action items in next retrospective'")
        
            if missing:
                errors.append(f"[X] Retrospective Analysis is missing: {', '.join(missing)}")
            else:
                checks_passed.append(f"[C] Retrospective Analysis is has")
        
            return TaskScore(
                score=1.0 if len(errors) == 0 else 0.0,
                metadata=ScoreMetadata(
                    success_accumulator=list(dict.fromkeys(checks_passed)),
                    error_accumulator=list(dict.fromkeys(errors)),
                )
            )
    
        except Exception as e:
            errors.append(f"[X] Error validating Retrospective Analysis: {str(e)}")
            return TaskScore(
                score=0.0,
                metadata=ScoreMetadata(
                    success_accumulator=list(dict.fromkeys(checks_passed)),
                    error_accumulator=list(dict.fromkeys(errors)),
                )
            )

    # -----------------------------------------------------------------------------
    # add-language-statistics-v2
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_add_language_statistics(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validates the Language Statistics section addition to Code Examples Repository.
    
    Requirements:
    1. heading_2 '📊 Language Statistics' appears after 'Rust Examples'
    2. Paragraph shows 'Total programming languages covered: 8'
    3. Gray callout with no icon contains today's date
    4. Numbered list contains exactly 8 languages in order
    5. Each list item follows '[NUMBER]. [LANGUAGE]: Ready for use' format
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    try:
        try:
            # Find Code Examples Repository page
            code_pages = _get_pages(backend, "Code Examples Repository")
            if not code_pages:
                errors.append("[X] Code Examples Repository page not found")
            else:
                checks_passed.append("[C] Code Examples Repository page found")
        
            page = code_pages[0]
            page_id = page.get("_id")
            blocks = _get_blocks(backend, page_id)
        
            if not blocks:
                errors.append("[X] Code Examples Repository page has no blocks")
            else:
                checks_passed.append("[C] Code Examples Repository page has blocks")
        
            missing = []
        
            # Track positions
            rust_examples_index = -1
            language_stats_index = -1
        
            # Track required elements
            has_language_stats_heading = False
            has_total_paragraph = False
            has_gray_callout = False
            callout_has_date = False
        
            # Track numbered list items
            expected_languages = ["Javascript", "Python", "Typescript", "Bash", "Sql", "Go", "Rust", "Java"]
            found_languages = []
        
            # Count heading_2 blocks with 'Examples' (should be 8)
            examples_count = 0
        
            for i, block in enumerate(blocks):
                block_type = block.get("type", "")
                content = block.get("content", "")
                properties = block.get("properties", {})
            
                # Count Examples headings
                if block_type == "heading2" and "Examples" in content:
                    examples_count += 1
            
                # Track Rust Examples position
                if block_type == "heading2" and "Rust Examples" in content:
                    rust_examples_index = i
            
                # Check for Language Statistics heading
                if block_type == "heading2" and "📊" in content and "Language Statistics" in content:
                    has_language_stats_heading = True
                    language_stats_index = i
            
                # Check for total paragraph
                if block_type == "paragraph":
                    if "Total programming languages covered:" in content and "8" in content:
                        has_total_paragraph = True
            
                # Check for gray callout
                if block_type == "callout":
                    bg_color = properties.get("backgroundColor", "")
                    icon = properties.get("icon", "")
                
                    if "gray" in bg_color.lower():
                        has_gray_callout = True
                        # Check for date (various formats)
                        if "Last updated:" in content or "updated" in content.lower():
                            if "2024" in content or "2025" in content or "2026" in content or "January" in content or "Jan" in content:
                                callout_has_date = True
            
                # Check numbered list items
                if block_type == "numberedList":
                    if "Ready for use" in content:
                        # Extract language name
                        for lang in expected_languages:
                            if lang in content or lang.lower() in content.lower():
                                if lang not in found_languages:
                                    found_languages.append(lang)
                                break
        
            # Validate positioning
            if rust_examples_index >= 0 and language_stats_index >= 0:
                if language_stats_index <= rust_examples_index:
                    missing.append("'📊 Language Statistics' should appear AFTER 'Rust Examples'")
        
            # Validate elements
            if not has_language_stats_heading:
                missing.append("heading_2 '📊 Language Statistics'")
        
            if not has_total_paragraph:
                missing.append("paragraph with 'Total programming languages covered: 8'")
        
            if not has_gray_callout:
                missing.append("callout with gray_background")
            elif not callout_has_date:
                missing.append("callout with 'Last updated:' and date")
        
            # Validate numbered list
            if len(found_languages) < 8:
                missing.append(f"numbered list should have 8 languages (found {len(found_languages)})")
        
            if missing:
                errors.append(f"[X] Language Statistics section is missing: {', '.join(missing)}")
            else:
                checks_passed.append(f"[C] Language Statistics section is has")
        
            return TaskScore(
                score=1.0 if len(errors) == 0 else 0.0,
                metadata=ScoreMetadata(
                    success_accumulator=list(dict.fromkeys(checks_passed)),
                    error_accumulator=list(dict.fromkeys(errors)),
                )
            )
    
        except Exception as e:
            errors.append(f"[X] Error validating Language Statistics section: {str(e)}")
            return TaskScore(
                score=0.0,
                metadata=ScoreMetadata(
                    success_accumulator=list(dict.fromkeys(checks_passed)),
                    error_accumulator=list(dict.fromkeys(errors)),
                )
            )

    # -----------------------------------------------------------------------------
    # restructure-handbook-sections-v2
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_restructure_handbook_sections(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validates the Company Handbook restructuring.
    
    Requirements:
    1. 'Benefits' section appears before 'Our Values' section (swapped)
    2. Orange callout with ⚠️ appears between 'Time Off' heading and its paragraph
    3. Divider at end followed by italic paragraph with dates
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    try:
        try:
            # Find Company Handbook page
            handbook_pages = _get_pages(backend, "Company Handbook")
            if not handbook_pages:
                errors.append("[X] Company Handbook page not found")
            else:
                checks_passed.append("[C] Company Handbook page found")
        
            page = handbook_pages[0]
            page_id = page.get("_id")
            blocks = _get_blocks(backend, page_id)
        
            if not blocks:
                errors.append("[X] Company Handbook page has no blocks")
            else:
                checks_passed.append("[C] Company Handbook page has blocks")
        
            missing = []
        
            # Track positions
            our_values_index = -1
            benefits_index = -1
            time_off_index = -1
        
            # Track required elements
            has_orange_callout = False
            callout_has_warning_icon = False
            callout_has_pto_text = False
            callout_after_time_off = False
            has_divider_at_end = False
            has_review_paragraph = False
            paragraph_is_italic = False
        
            for i, block in enumerate(blocks):
                block_type = block.get("type", "")
                content = block.get("content", "")
                properties = block.get("properties", {})
            
                # Track section positions
                if block_type == "heading2" and "Our Values" in content:
                    our_values_index = i
            
                if block_type == "heading2" and "Benefits" in content:
                    benefits_index = i
            
                # Track Time Off heading
                if block_type == "heading3" and "Time Off" in content:
                    time_off_index = i
            
                # Check for orange callout with PTO text
                if block_type == "callout":
                    bg_color = properties.get("backgroundColor", "")
                    icon = properties.get("icon", "")
                
                    if "orange" in bg_color.lower():
                        has_orange_callout = True
                        if icon == "⚠️":
                            callout_has_warning_icon = True
                        if "PTO" in content or "2 weeks" in content or "advance" in content.lower():
                            callout_has_pto_text = True
                        # Check if it's after Time Off
                        if time_off_index >= 0 and i > time_off_index:
                            callout_after_time_off = True
            
                # Check for divider near end
                if block_type == "divider":
                    # Check if it's close to end (within last 5 blocks)
                    if i >= len(blocks) - 5:
                        has_divider_at_end = True
            
                # Check for review paragraph
                if block_type == "paragraph":
                    if "Last reviewed:" in content or "reviewed" in content.lower():
                        if "Next review:" in content or "next review" in content.lower():
                            has_review_paragraph = True
                            # Check for italic
                            if properties.get("italic", False):
                                paragraph_is_italic = True
        
            # Validate section swapping
            if our_values_index >= 0 and benefits_index >= 0:
                if benefits_index >= our_values_index:
                    missing.append("'Benefits' section should appear BEFORE 'Our Values' (sections swapped)")
            else:
                if our_values_index < 0:
                    missing.append("'Our Values' section not found")
                if benefits_index < 0:
                    missing.append("'Benefits' section not found")
        
            # Validate callout
            if not has_orange_callout:
                missing.append("callout with orange_background")
            else:
                if not callout_has_warning_icon:
                    missing.append("callout with ⚠️ icon")
                if not callout_has_pto_text:
                    missing.append("callout with PTO policy text")
                if not callout_after_time_off:
                    missing.append("callout should appear after 'Time Off' heading")
        
            # Validate end elements
            if not has_divider_at_end:
                missing.append("divider near end of page")
        
            if not has_review_paragraph:
                missing.append("paragraph with 'Last reviewed:' and 'Next review:' dates")
            elif not paragraph_is_italic:
                # Be lenient about italic - some implementations may vary
                pass
        
            if missing:
                errors.append(f"[X] Handbook restructuring is missing: {', '.join(missing)}")
            else:
                checks_passed.append(f"[C] Handbook restructuring is has")
        
            return TaskScore(
                score=1.0 if len(errors) == 0 else 0.0,
                metadata=ScoreMetadata(
                    success_accumulator=list(dict.fromkeys(checks_passed)),
                    error_accumulator=list(dict.fromkeys(errors)),
                )
            )
    
        except Exception as e:
            errors.append(f"[X] Error validating Handbook restructuring: {str(e)}")
            return TaskScore(
                score=0.0,
                metadata=ScoreMetadata(
                    success_accumulator=list(dict.fromkeys(checks_passed)),
                    error_accumulator=list(dict.fromkeys(errors)),
                )
            )

    # -----------------------------------------------------------------------------
    # add-advanced-features-section-v2
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_add_advanced_features_section(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validates the addition of Advanced Features section to Getting Started page.
    
    Requirements:
    1. 'Advanced Features' heading2 appears after 'Key Features' section
    2. Yellow callout with NO icon and exact text with emoji
    3. Three unchecked todos with exact text and emojis
    4. Divider after the todos
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    try:
        try:
            # Find Getting Started page
            pages = _get_pages(backend, "Getting Started")
            if not pages:
                errors.append("[X] Getting Started page not found")
            else:
                checks_passed.append("[C] Getting Started page found")
        
            page = pages[0]
            page_id = page.get("_id")
            blocks = _get_blocks(backend, page_id)
        
            if not blocks:
                errors.append("[X] Getting Started page has no blocks")
            else:
                checks_passed.append("[C] Getting Started page has blocks")
        
            missing = []
        
            # Track positions and required elements
            key_features_index = -1
            advanced_features_index = -1
            callout_index = -1
            todo_indices = []
            divider_index = -1
        
            # Required content
            expected_callout_text = "⚡ Pro tip: These features require a premium subscription"
            expected_todos = [
                "🔐 Enable end-to-end encryption",
                "📊 Access advanced analytics dashboard",
                "🤝 Set up team collaboration spaces"
            ]
        
            for i, block in enumerate(blocks):
                block_type = block.get("type", "")
                content = block.get("content", "")
                properties = block.get("properties", {})
            
                # Track Key Features position
                if block_type == "heading2" and "Key Features" in content:
                    key_features_index = i
            
                # Track Advanced Features position
                if block_type == "heading2" and "Advanced Features" in content:
                    advanced_features_index = i
            
                # Check for yellow callout with exact text
                if block_type == "callout":
                    bg_color = properties.get("backgroundColor", "")
                    icon = properties.get("icon")
                    if "yellow" in bg_color.lower() and expected_callout_text in content:
                        if icon is None or icon == "":
                            callout_index = i
                        else:
                            # Callout found but has an icon
                            pass
            
                # Check for todos
                if block_type == "todo":
                    for expected_todo in expected_todos:
                        if expected_todo in content and not properties.get("checked", False):
                            todo_indices.append(i)
            
                # Track divider
                if block_type == "divider":
                    divider_index = i
        
            # Validate Advanced Features heading exists and position
            if advanced_features_index < 0:
                missing.append("'Advanced Features' heading2")
            elif key_features_index >= 0 and advanced_features_index <= key_features_index:
                missing.append("'Advanced Features' heading should appear AFTER 'Key Features'")
        
            # Validate callout
            if callout_index < 0:
                missing.append(f"yellow callout with no icon containing '{expected_callout_text}'")
            elif advanced_features_index >= 0 and callout_index <= advanced_features_index:
                missing.append("callout should appear AFTER 'Advanced Features' heading")
        
            # Validate todos
            if len(todo_indices) < 3:
                missing.append(f"3 unchecked todos (found {len(todo_indices)})")
        
            # Validate divider comes after todos
            if divider_index < 0:
                missing.append("divider after todos")
            elif todo_indices and divider_index <= max(todo_indices):
                missing.append("divider should appear AFTER all todos")
        
            if missing:
                errors.append(f"[X] Advanced Features section is missing: {', '.join(missing)}")
            else:
                checks_passed.append(f"[C] Advanced Features section is has")
        
            return TaskScore(
                score=1.0 if len(errors) == 0 else 0.0,
                metadata=ScoreMetadata(
                    success_accumulator=list(dict.fromkeys(checks_passed)),
                    error_accumulator=list(dict.fromkeys(errors)),
                )
            )
    
        except Exception as e:
            errors.append(f"[X] Error validating Advanced Features section: {str(e)}")
            return TaskScore(
                score=0.0,
                metadata=ScoreMetadata(
                    success_accumulator=list(dict.fromkeys(checks_passed)),
                    error_accumulator=list(dict.fromkeys(errors)),
                )
            )

    # -----------------------------------------------------------------------------
    # enhance-team-retrospective-v2
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_enhance_team_retrospective(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validates the enhancement of Team Retrospective page.
    
    Requirements:
    1. 'Velocity Metrics' heading3 between 'What went well' and 'What could be improved'
    2. Code block with JSON content after the heading
    3. 'What went well' bullets prefixed with '🟢 '
    4. 'What could be improved' bullets prefixed with '🟡 '
    5. Bookmark with exact URL and caption after quote
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    try:
        try:
            # Find Team Retrospective page
            pages = _get_pages(backend, "Team Retrospective")
            if not pages:
                errors.append("[X] Team Retrospective page not found")
            else:
                checks_passed.append("[C] Team Retrospective page found")
        
            page = pages[0]
            page_id = page.get("_id")
            blocks = _get_blocks(backend, page_id)
        
            if not blocks:
                errors.append("[X] Team Retrospective page has no blocks")
            else:
                checks_passed.append("[C] Team Retrospective page has blocks")
        
            missing = []
        
            # Track positions
            went_well_index = -1
            could_be_improved_index = -1
            velocity_metrics_index = -1
            quote_index = -1
        
            # Track required elements
            has_json_code_block = False
            has_bookmark = False
            green_bullets_count = 0
            yellow_bullets_count = 0
            went_well_bullets = 0
            improvement_bullets = 0
        
            expected_json = '{"velocity": 42, "planned": 45, "completed": 42}'
            expected_url = "https://retrospectivewiki.org/index.php?title=Agile_Retrospective_Resource_Wiki"
            expected_caption = "Retrospective techniques reference"
        
            in_went_well_section = False
            in_improvement_section = False
        
            for i, block in enumerate(blocks):
                block_type = block.get("type", "")
                content = block.get("content", "")
                properties = block.get("properties", {})
            
                # Track section positions
                if block_type == "heading2":
                    if "What went well" in content:
                        went_well_index = i
                        in_went_well_section = True
                        in_improvement_section = False
                    elif "What could be improved" in content:
                        could_be_improved_index = i
                        in_went_well_section = False
                        in_improvement_section = True
                    else:
                        in_went_well_section = False
                        in_improvement_section = False
            
                # Track Velocity Metrics heading3
                if block_type == "heading3" and "Velocity Metrics" in content:
                    velocity_metrics_index = i
            
                # Check for JSON code block
                if block_type == "code":
                    lang = properties.get("language", "")
                    if lang.lower() == "json" and expected_json in content:
                        has_json_code_block = True
            
                # Track quote position
                if block_type == "quote":
                    quote_index = i
            
                # Check bookmark
                if block_type == "bookmark":
                    url = properties.get("url", "")
                    caption = properties.get("caption", "")
                    if expected_url in url and expected_caption in caption:
                        has_bookmark = True
            
                # Count bullets in sections and check for emojis
                if block_type == "bulletedList":
                    if in_went_well_section:
                        went_well_bullets += 1
                        if content.startswith("🟢"):
                            green_bullets_count += 1
                    elif in_improvement_section:
                        improvement_bullets += 1
                        if content.startswith("🟡"):
                            yellow_bullets_count += 1
        
            # Validate Velocity Metrics position
            if velocity_metrics_index < 0:
                missing.append("'📈 Velocity Metrics' heading3")
            elif went_well_index >= 0 and could_be_improved_index >= 0:
                if not (went_well_index < velocity_metrics_index < could_be_improved_index):
                    missing.append("'Velocity Metrics' should be between 'What went well' and 'What could be improved'")
        
            # Validate JSON code block
            if not has_json_code_block:
                missing.append(f"code block with JSON: {expected_json}")
        
            # Validate green emoji prefixes
            if went_well_bullets > 0 and green_bullets_count < went_well_bullets:
                missing.append(f"🟢 prefix on 'went well' bullets ({green_bullets_count}/{went_well_bullets})")
        
            # Validate yellow emoji prefixes
            if improvement_bullets > 0 and yellow_bullets_count < improvement_bullets:
                missing.append(f"🟡 prefix on 'improvement' bullets ({yellow_bullets_count}/{improvement_bullets})")
        
            # Validate bookmark
            if not has_bookmark:
                missing.append(f"bookmark with URL '{expected_url}' and caption '{expected_caption}'")
        
            if missing:
                errors.append(f"[X] Team Retrospective enhancement is missing: {', '.join(missing)}")
            else:
                checks_passed.append(f"[C] Team Retrospective enhancement is has")
        
            return TaskScore(
                score=1.0 if len(errors) == 0 else 0.0,
                metadata=ScoreMetadata(
                    success_accumulator=list(dict.fromkeys(checks_passed)),
                    error_accumulator=list(dict.fromkeys(errors)),
                )
            )
    
        except Exception as e:
            errors.append(f"[X] Error validating Team Retrospective enhancement: {str(e)}")
            return TaskScore(
                score=0.0,
                metadata=ScoreMetadata(
                    success_accumulator=list(dict.fromkeys(checks_passed)),
                    error_accumulator=list(dict.fromkeys(errors)),
                )
            )

    # -----------------------------------------------------------------------------
    # create-workspace-activity-dashboard-v2
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_create_workspace_activity_dashboard(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validates the creation of Workspace Activity Dashboard.
    
    Requirements:
    1. New page titled '🚀 Workspace Activity Dashboard' exists at root
    2. heading_1 '📊 Workspace Activity Summary'
    3. Green callout with 📅 icon and date
    4. heading_2 '✅ Task Completion Overview' with stats paragraph
    5. heading_3 sections for each analyzed page with bulleted stats
    6. heading_2 '🎯 Priority Actions' with numbered list of Bug Tracker unchecked todos
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    try:
        try:
            # Find the dashboard page by querying all pages and finding by partial match
            all_pages_result = backend.query({"collection": "pages", "filter": {}})
            all_pages = all_pages_result if isinstance(all_pages_result, list) else []
        
            dashboard_pages = [p for p in all_pages if "Activity Dashboard" in p.get("title", "")]
            if not dashboard_pages:
                errors.append("[X] Workspace Activity Dashboard page not found")
            else:
                checks_passed.append("[C] Workspace Activity Dashboard page found")
        
            page = dashboard_pages[0]
            page_id = page.get("_id")
            blocks = _get_blocks(backend, page_id)
        
            if not blocks:
                errors.append("[X] Workspace Activity Dashboard page has no blocks")
            else:
                checks_passed.append("[C] Workspace Activity Dashboard page has blocks")
        
            missing = []
        
            # Track required elements
            has_summary_heading = False
            has_green_callout = False
            has_task_completion_heading = False
            has_combined_stats_paragraph = False
            page_sections_found = 0
            has_priority_heading = False
            has_numbered_list = False
        
            for i, block in enumerate(blocks):
                block_type = block.get("type", "")
                content = block.get("content", "")
                properties = block.get("properties", {})
            
                # Check heading1 - Activity Summary
                if block_type == "heading1" and "Workspace Activity Summary" in content:
                    has_summary_heading = True
            
                # Check green callout with date icon
                if block_type == "callout":
                    bg_color = properties.get("backgroundColor", "")
                    icon = properties.get("icon", "")
                    if "green" in bg_color.lower() and icon == "📅":
                        if "Dashboard generated" in content or "generated" in content.lower():
                            has_green_callout = True
            
                # Check Task Completion Overview heading
                if block_type == "heading2" and "Task Completion Overview" in content:
                    has_task_completion_heading = True
            
                # Check combined stats paragraph
                if block_type == "paragraph":
                    if "Combined tasks" in content or "Completed" in content:
                        if "%" in content:
                            has_combined_stats_paragraph = True
            
                # Check page status sections (heading3)
                if block_type == "heading3":
                    if any(name in content for name in ["Getting Started", "Bug Tracker", "Feature Requests"]):
                        page_sections_found += 1
            
                # Check Priority Actions heading
                if block_type == "heading2" and "Priority Actions" in content:
                    has_priority_heading = True
            
                # Check for numbered list (Bug Tracker todos)
                if block_type == "numberedList":
                    has_numbered_list = True
        
            # Validate all requirements
            if not has_summary_heading:
                missing.append("heading_1 '📊 Workspace Activity Summary'")
        
            if not has_green_callout:
                missing.append("green callout with 📅 icon and date text")
        
            if not has_task_completion_heading:
                missing.append("heading_2 '✅ Task Completion Overview'")
        
            if not has_combined_stats_paragraph:
                missing.append("paragraph with combined task statistics")
        
            if page_sections_found < 3:
                missing.append(f"heading_3 sections for all 3 pages (found {page_sections_found})")
        
            if not has_priority_heading:
                missing.append("heading_2 '🎯 Priority Actions'")
        
            if not has_numbered_list:
                missing.append("numbered list with Bug Tracker unchecked todos")
        
            if missing:
                errors.append(f"[X] Workspace Activity Dashboard is missing: {', '.join(missing)}")
            else:
                checks_passed.append(f"[C] Workspace Activity Dashboard is has")
        
            return TaskScore(
                score=1.0 if len(errors) == 0 else 0.0,
                metadata=ScoreMetadata(
                    success_accumulator=list(dict.fromkeys(checks_passed)),
                    error_accumulator=list(dict.fromkeys(errors)),
                )
            )
    
        except Exception as e:
            errors.append(f"[X] Error validating Workspace Activity Dashboard: {str(e)}")
            return TaskScore(
                score=0.0,
                metadata=ScoreMetadata(
                    success_accumulator=list(dict.fromkeys(checks_passed)),
                    error_accumulator=list(dict.fromkeys(errors)),
                )
            )

    # -----------------------------------------------------------------------------
    # add-development-best-practices-v2
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_add_development_best_practices(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validates the addition of Development Best Practices section to Engineering Wiki.
    
    Requirements:
    1. Divider appears after Development Setup numbered list
    2. heading2 '🔧 Development Best Practices'
    3. Orange callout with ⚠️ icon and exact text
    4. heading3 '📝 Code Style Guidelines' with 4 numbered list items
    5. heading3 '🔄 Git Workflow' with 4 bulleted list items
    6. Quote block with exact text
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    try:
        try:
            # Find Engineering Wiki page
            wiki_pages = _get_pages(backend, "Engineering Wiki")
            if not wiki_pages:
                errors.append("[X] Engineering Wiki page not found")
            else:
                checks_passed.append("[C] Engineering Wiki page found")
        
            page = wiki_pages[0]
            page_id = page.get("_id")
            blocks = _get_blocks(backend, page_id)
        
            if not blocks:
                errors.append("[X] Engineering Wiki page has no blocks")
            else:
                checks_passed.append("[C] Engineering Wiki page has blocks")
        
            missing = []
        
            # Find the Development Setup section and check divider follows
            dev_setup_idx = -1
            for i, block in enumerate(blocks):
                if block.get("type") == "heading2" and block.get("content") == "Development Setup":
                    dev_setup_idx = i
                    break
        
            if dev_setup_idx == -1:
                missing.append("Development Setup section not found")
            else:
                # Find where the numbered list ends after Development Setup
                last_numbered_idx = dev_setup_idx
                for i in range(dev_setup_idx + 1, len(blocks)):
                    if blocks[i].get("type") == "numberedList":
                        last_numbered_idx = i
                    elif blocks[i].get("type") not in ["numberedList"]:
                        break
            
                # Check if divider comes after the numbered list
                divider_found = False
                if last_numbered_idx + 1 < len(blocks):
                    if blocks[last_numbered_idx + 1].get("type") == "divider":
                        divider_found = True
            
                if not divider_found:
                    missing.append("divider after Development Setup section")
        
            # Check for heading2 'Development Best Practices'
            best_practices_heading = None
            for i, block in enumerate(blocks):
                if block.get("type") == "heading2" and "Development Best Practices" in block.get("content", ""):
                    best_practices_heading = i
                    break
        
            if best_practices_heading is None:
                missing.append("heading2 '🔧 Development Best Practices'")
        
            # Check for orange callout with warning icon
            callout_found = False
            for block in blocks:
                if block.get("type") == "callout":
                    props = block.get("properties", {})
                    content = block.get("content", "")
                    if "orange" in props.get("backgroundColor", "").lower():
                        if props.get("icon") == "⚠️":
                            if "All developers must follow these practices" in content:
                                callout_found = True
                                break
        
            if not callout_found:
                missing.append("orange callout with ⚠️ icon and correct text")
        
            # Check for heading3 'Code Style Guidelines'
            code_style_idx = -1
            for i, block in enumerate(blocks):
                if block.get("type") == "heading3" and "Code Style Guidelines" in block.get("content", ""):
                    code_style_idx = i
                    break
        
            if code_style_idx == -1:
                missing.append("heading3 '📝 Code Style Guidelines'")
            else:
                # Check for 4 numbered list items after it
                numbered_items = []
                for i in range(code_style_idx + 1, min(code_style_idx + 10, len(blocks))):
                    if blocks[i].get("type") == "numberedList":
                        numbered_items.append(blocks[i].get("content", ""))
                    elif blocks[i].get("type") in ["heading2", "heading3"]:
                        break
            
                expected_items = [
                    "Use ESLint with our custom configuration",
                    "Format code with Prettier on save",
                    "Write unit tests for all new functions",
                    "Document complex logic with JSDoc comments"
                ]
            
                for expected in expected_items:
                    if not any(expected in item for item in numbered_items):
                        missing.append(f"numbered list item: '{expected}'")
        
            # Check for heading3 'Git Workflow'
            git_workflow_idx = -1
            for i, block in enumerate(blocks):
                if block.get("type") == "heading3" and "Git Workflow" in block.get("content", ""):
                    git_workflow_idx = i
                    break
        
            if git_workflow_idx == -1:
                missing.append("heading3 '🔄 Git Workflow'")
            else:
                # Check for 4 bulleted list items after it
                bullet_items = []
                for i in range(git_workflow_idx + 1, min(git_workflow_idx + 10, len(blocks))):
                    if blocks[i].get("type") == "bulletedList":
                        bullet_items.append(blocks[i].get("content", ""))
                    elif blocks[i].get("type") in ["heading2", "heading3", "quote"]:
                        break
            
                expected_bullets = [
                    "Create feature branches from develop",
                    "Write descriptive commit messages",
                    "Squash commits before merging",
                    "Request reviews from at least 2 team members"
                ]
            
                for expected in expected_bullets:
                    if not any(expected in item for item in bullet_items):
                        missing.append(f"bulleted list item: '{expected}'")
        
            # Check for quote block
            quote_found = False
            for block in blocks:
                if block.get("type") == "quote":
                    content = block.get("content", "")
                    if "Good code is not just working code" in content and "others can understand and maintain" in content:
                        quote_found = True
                        break
        
            if not quote_found:
                missing.append("quote block with exact philosophical message")
        
            if missing:
                errors.append(f"[X] Development Best Practices section is missing: {', '.join(missing)}")
            else:
                checks_passed.append(f"[C] Development Best Practices section is has")
        
            return TaskScore(
                score=1.0 if len(errors) == 0 else 0.0,
                metadata=ScoreMetadata(
                    success_accumulator=list(dict.fromkeys(checks_passed)),
                    error_accumulator=list(dict.fromkeys(errors)),
                )
            )
    
        except Exception as e:
            errors.append(f"[X] Error validating Development Best Practices: {str(e)}")
            return TaskScore(
                score=0.0,
                metadata=ScoreMetadata(
                    success_accumulator=list(dict.fromkeys(checks_passed)),
                    error_accumulator=list(dict.fromkeys(errors)),
                )
            )

    # -----------------------------------------------------------------------------
    # add-react-examples-section-3-v2
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_add_react_examples_section_3(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validates the addition of React Examples section to Code Examples Repository.
    
    Requirements:
    1. React Examples section appears between Typescript and Bash sections
    2. heading2 '⚛️ React Examples'
    3. Two JSX code blocks with Button component and useDebounce hook
    4. Descriptive paragraph
    5. Purple callout with 💡 icon and hooks reminder
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    try:
        try:
            # Find Code Examples Repository page
            code_pages = _get_pages(backend, "Code Examples Repository")
            if not code_pages:
                errors.append("[X] Code Examples Repository page not found")
            else:
                checks_passed.append("[C] Code Examples Repository page found")
        
            page = code_pages[0]
            page_id = page.get("_id")
            blocks = _get_blocks(backend, page_id)
        
            if not blocks:
                errors.append("[X] Code Examples Repository page has no blocks")
            else:
                checks_passed.append("[C] Code Examples Repository page has blocks")
        
            missing = []
        
            # Find Typescript and Bash section indices
            typescript_idx = -1
            bash_idx = -1
            react_idx = -1
        
            for i, block in enumerate(blocks):
                content = block.get("content", "")
                block_type = block.get("type", "")
            
                if block_type == "heading2":
                    if "Typescript Examples" in content:
                        typescript_idx = i
                    elif "Bash Examples" in content:
                        bash_idx = i
                    elif "React Examples" in content:
                        react_idx = i
        
            # Check React section exists
            if react_idx == -1:
                missing.append("heading2 '⚛️ React Examples'")
            else:
                # Check React is between Typescript and Bash
                if typescript_idx != -1 and bash_idx != -1:
                    if not (typescript_idx < react_idx < bash_idx):
                        missing.append("React Examples section not positioned between Typescript and Bash")
        
            # Check for JSX code blocks
            jsx_code_blocks = []
            for block in blocks:
                if block.get("type") == "code":
                    props = block.get("properties", {})
                    if props.get("language", "").lower() in ["jsx", "javascript"]:
                        jsx_code_blocks.append(block.get("content", ""))
        
            # Check Button component code
            button_found = False
            for code in jsx_code_blocks:
                if "Button" in code and "onClick" in code and "variant" in code:
                    button_found = True
                    break
        
            if not button_found:
                missing.append("JSX code block with Button component")
        
            # Check useDebounce hook code
            debounce_found = False
            for code in jsx_code_blocks:
                if "useDebounce" in code and "useState" in code and "setTimeout" in code:
                    debounce_found = True
                    break
        
            if not debounce_found:
                missing.append("JSX code block with useDebounce hook")
        
            # Check for descriptive paragraph
            paragraph_found = False
            for block in blocks:
                if block.get("type") == "paragraph":
                    content = block.get("content", "")
                    if "React" in content and "component" in content.lower():
                        paragraph_found = True
                        break
        
            if not paragraph_found:
                missing.append("paragraph about React component pattern")
        
            # Check for purple callout with hooks reminder
            callout_found = False
            for block in blocks:
                if block.get("type") == "callout":
                    props = block.get("properties", {})
                    content = block.get("content", "")
                    if "purple" in props.get("backgroundColor", "").lower():
                        if props.get("icon") == "💡":
                            if "Rules of Hooks" in content or "hooks" in content.lower():
                                callout_found = True
                                break
        
            if not callout_found:
                missing.append("purple callout with 💡 icon and hooks reminder")
        
            if missing:
                errors.append(f"[X] React Examples section is missing: {', '.join(missing)}")
            else:
                checks_passed.append(f"[C] React Examples section is has")
        
            return TaskScore(
                score=1.0 if len(errors) == 0 else 0.0,
                metadata=ScoreMetadata(
                    success_accumulator=list(dict.fromkeys(checks_passed)),
                    error_accumulator=list(dict.fromkeys(errors)),
                )
            )
    
        except Exception as e:
            errors.append(f"[X] Error validating React Examples section: {str(e)}")
            return TaskScore(
                score=0.0,
                metadata=ScoreMetadata(
                    success_accumulator=list(dict.fromkeys(checks_passed)),
                    error_accumulator=list(dict.fromkeys(errors)),
                )
            )

    # -----------------------------------------------------------------------------
    # reorganize-handbook-with-performance-v2
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_reorganize_handbook_with_performance(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validates the reorganization of Company Handbook with Performance Standards.
    
    Requirements:
    1. Benefits section appears before Our Values (swapped positions)
    2. Our Values section appears after Benefits
    3. Performance Standards section exists between Our Values and Work Policies
    4. Remote Work subsection contains yellow callout with policy text
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    try:
        try:
            # Find Company Handbook page
            handbook_pages = _get_pages(backend, "Company Handbook")
            if not handbook_pages:
                errors.append("[X] Company Handbook page not found")
            else:
                checks_passed.append("[C] Company Handbook page found")
        
            page = handbook_pages[0]
            page_id = page.get("_id")
            blocks = _get_blocks(backend, page_id)
        
            if not blocks:
                errors.append("[X] Company Handbook page has no blocks")
            else:
                checks_passed.append("[C] Company Handbook page has blocks")
        
            missing = []
        
            # Find section indices
            benefits_idx = -1
            our_values_idx = -1
            performance_idx = -1
            work_policies_idx = -1
            remote_work_idx = -1
        
            for i, block in enumerate(blocks):
                content = block.get("content", "")
                block_type = block.get("type", "")
            
                if block_type == "heading2":
                    if content == "Benefits":
                        benefits_idx = i
                    elif content == "Our Values":
                        our_values_idx = i
                    elif "Performance Standards" in content:
                        performance_idx = i
                    elif content == "Work Policies":
                        work_policies_idx = i
                elif block_type == "heading3":
                    if content == "Remote Work":
                        remote_work_idx = i
        
            # Check Benefits appears before Our Values (swapped)
            if benefits_idx == -1:
                missing.append("Benefits section not found")
            if our_values_idx == -1:
                missing.append("Our Values section not found")
        
            if benefits_idx != -1 and our_values_idx != -1:
                if benefits_idx > our_values_idx:
                    missing.append("Benefits should appear BEFORE Our Values (sections should be swapped)")
        
            # Check Performance Standards exists
            if performance_idx == -1:
                missing.append("heading2 '🎯 Performance Standards'")
        
            # Check Performance Standards is between Our Values and Work Policies
            if performance_idx != -1 and our_values_idx != -1 and work_policies_idx != -1:
                if not (our_values_idx < performance_idx < work_policies_idx):
                    missing.append("Performance Standards should be between Our Values and Work Policies")
        
            # Check Performance Standards content
            if performance_idx != -1:
                # Check for paragraph
                paragraph_found = False
                for i in range(performance_idx + 1, min(performance_idx + 10, len(blocks))):
                    if blocks[i].get("type") == "paragraph":
                        if "evaluated" in blocks[i].get("content", "").lower():
                            paragraph_found = True
                            break
                    elif blocks[i].get("type") == "heading2":
                        break
            
                if not paragraph_found:
                    missing.append("paragraph about evaluation criteria")
            
                # Check for numbered list items
                expected_items = [
                    "Quality of deliverables",
                    "Team collaboration",
                    "Innovation and problem-solving",
                    "Meeting deadlines"
                ]
            
                numbered_items = []
                for i in range(performance_idx + 1, min(performance_idx + 15, len(blocks))):
                    if blocks[i].get("type") == "numberedList":
                        numbered_items.append(blocks[i].get("content", ""))
                    elif blocks[i].get("type") == "heading2":
                        break
            
                for expected in expected_items:
                    if not any(expected in item for item in numbered_items):
                        missing.append(f"numbered list item: '{expected}'")
        
            # Check for yellow callout in Remote Work section
            if remote_work_idx != -1:
                callout_found = False
                for i in range(remote_work_idx + 1, min(remote_work_idx + 10, len(blocks))):
                    block = blocks[i]
                    if block.get("type") == "heading3" or block.get("type") == "heading2":
                        break
                    if block.get("type") == "callout":
                        props = block.get("properties", {})
                        content = block.get("content", "")
                        if "yellow" in props.get("backgroundColor", "").lower():
                            if props.get("icon") == "💻":
                                if "Mandatory weekly team sync" in content or "Wednesdays" in content:
                                    callout_found = True
                                    break
            
                if not callout_found:
                    missing.append("yellow callout with 💻 icon in Remote Work section")
            else:
                missing.append("Remote Work subsection not found")
        
            if missing:
                errors.append(f"[X] Handbook reorganization is missing: {', '.join(missing)}")
            else:
                checks_passed.append(f"[C] Handbook reorganization is has")
        
            return TaskScore(
                score=1.0 if len(errors) == 0 else 0.0,
                metadata=ScoreMetadata(
                    success_accumulator=list(dict.fromkeys(checks_passed)),
                    error_accumulator=list(dict.fromkeys(errors)),
                )
            )
    
        except Exception as e:
            errors.append(f"[X] Error validating Handbook reorganization: {str(e)}")
            return TaskScore(
                score=0.0,
                metadata=ScoreMetadata(
                    success_accumulator=list(dict.fromkeys(checks_passed)),
                    error_accumulator=list(dict.fromkeys(errors)),
                )
            )

    # -----------------------------------------------------------------------------
    # add-code-examples-after-tips-v2
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_add_code_examples_after_tips(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validates code blocks added after yellow Tip callouts.
    
    Requirements:
    1. Each yellow_background callout must be followed by a typescript code block
    2. Page ends with heading_1 'Guideline Statistics' and two paragraphs
    3. Tips count must match the actual number of yellow callouts
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    try:
        try:
            # Find Project Guidelines page
            guidelines_pages = _get_pages(backend, "Project Guidelines & Best Practices")
            if not guidelines_pages:
                errors.append("[X] Project Guidelines & Best Practices page not found")
            else:
                checks_passed.append("[C] Project Guidelines & Best Practices page found")
        
            page = guidelines_pages[0]
            page_id = page.get("_id")
            blocks = _get_blocks(backend, page_id)
        
            if not blocks:
                errors.append("[X] Project Guidelines page has no blocks")
            else:
                checks_passed.append("[C] Project Guidelines page has blocks")
        
            missing = []
        
            # Find all yellow callouts and check each is followed by code block
            yellow_callout_count = 0
            code_blocks_after_yellow = 0
        
            for i, block in enumerate(blocks):
                if block.get("type") == "callout":
                    props = block.get("properties", {})
                    if props.get("backgroundColor") == "yellow_background":
                        yellow_callout_count += 1
                        # Check if next block is a code block
                        if i + 1 < len(blocks):
                            next_block = blocks[i + 1]
                            if next_block.get("type") == "code":
                                next_props = next_block.get("properties", {})
                                if next_props.get("language", "").lower() == "typescript":
                                    content = next_block.get("content", "")
                                    if "runTests" in content and "testRunner" in content:
                                        code_blocks_after_yellow += 1
        
            if yellow_callout_count == 0:
                missing.append("no yellow callouts found")
            elif code_blocks_after_yellow < yellow_callout_count:
                missing.append(f"only {code_blocks_after_yellow}/{yellow_callout_count} yellow callouts have code blocks after them")
        
            # Check for statistics section at the end
            stats_heading_found = False
            total_guidelines_found = False
            tips_added_found = False
        
            # Look at last few blocks
            for i in range(max(0, len(blocks) - 5), len(blocks)):
                block = blocks[i]
                content = block.get("content", "")
                block_type = block.get("type", "")
            
                if block_type == "heading1" and "Guideline Statistics" in content:
                    stats_heading_found = True
                elif block_type == "paragraph":
                    if "Total guidelines: 31" in content:
                        total_guidelines_found = True
                    elif "Tips added:" in content:
                        # Verify the count matches
                        if str(yellow_callout_count) in content or f"Tips added: {yellow_callout_count}" in content:
                            tips_added_found = True
        
            if not stats_heading_found:
                missing.append("heading_1 '📊 Guideline Statistics' at end")
            if not total_guidelines_found:
                missing.append("paragraph with 'Total guidelines: 31'")
            if not tips_added_found:
                missing.append(f"paragraph with 'Tips added: {yellow_callout_count}'")
        
            if missing:
                errors.append(f"[X] Code examples task is missing: {', '.join(missing)}")
            else:
                checks_passed.append(f"[C] Code examples task is has")
        
            return TaskScore(
                score=1.0 if len(errors) == 0 else 0.0,
                metadata=ScoreMetadata(
                    success_accumulator=list(dict.fromkeys(checks_passed)),
                    error_accumulator=list(dict.fromkeys(errors)),
                )
            )
    
        except Exception as e:
            errors.append(f"[X] Error validating code examples: {str(e)}")
            return TaskScore(
                score=0.0,
                metadata=ScoreMetadata(
                    success_accumulator=list(dict.fromkeys(checks_passed)),
                    error_accumulator=list(dict.fromkeys(errors)),
                )
            )

    # -----------------------------------------------------------------------------
    # add-user-story-analysis-v2
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_add_user_story_analysis(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validates the User Story Analysis subsection added to the PRD page.
    
    Requirements:
    1. New content appears between User Stories Part 2 and Part 3
    2. heading_3 '🔍 User Story Analysis' exists
    3. Yellow callout with 📊 icon and analysis text exists
    4. Numbered list with accurate counts (3 parts, 9 bullets, avg 3, none need expansion)
    5. heading_3 '✅ User Story Checklist' exists
    6. Five unchecked todos with exact text
    7. Quote block at the end of the subsection
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    try:
        try:
            # Find the PRD page
            prd_pages = _get_pages(backend, "Comprehensive Product Requirements Document")
            if not prd_pages:
                errors.append("[X] Comprehensive Product Requirements Document page not found")
            else:
                checks_passed.append("[C] Comprehensive Product Requirements Document page found")
        
            page = prd_pages[0]
            page_id = page.get("_id")
            blocks = _get_blocks(backend, page_id)
        
            if not blocks:
                errors.append("[X] PRD page has no blocks")
            else:
                checks_passed.append("[C] PRD page has blocks")
        
            missing = []
        
            # Find User Stories Part 2 and Part 3 positions
            part2_index = None
            part3_index = None
        
            for i, block in enumerate(blocks):
                content = block.get("content", "")
                if block.get("type") == "heading3":
                    if "User Stories - Part 2" in content:
                        part2_index = i
                    elif "User Stories - Part 3" in content:
                        part3_index = i
        
            if part2_index is None:
                missing.append("User Stories - Part 2 heading not found")
            if part3_index is None:
                missing.append("User Stories - Part 3 heading not found")
        
            if part2_index is not None and part3_index is not None:
                # Check new content exists between Part 2 and Part 3
                analysis_heading_found = False
                analysis_callout_found = False
                numbered_list_found = False
                checklist_heading_found = False
                todos_found = 0
                quote_found = False
            
                # Expected todo texts (without checkbox prefix)
                expected_todos = [
                    "Validate with customer advisory board",
                    "Map stories to technical requirements",
                    "Prioritize based on business value",
                    "Estimate implementation effort",
                    "Create acceptance criteria"
                ]
            
                for i in range(part2_index + 1, part3_index):
                    block = blocks[i]
                    block_type = block.get("type", "")
                    content = block.get("content", "")
                    props = block.get("properties", {})
                
                    if block_type == "heading3":
                        if "User Story Analysis" in content:
                            analysis_heading_found = True
                        elif "User Story Checklist" in content:
                            checklist_heading_found = True
                
                    if block_type == "callout":
                        if props.get("backgroundColor") == "yellow_background":
                            if props.get("icon") == "📊" and "Analysis based on current user story inventory" in content:
                                analysis_callout_found = True
                
                    if block_type == "numberedList":
                        # Check for analysis content
                        if "Total user story sections:" in content or "Total user requirements:" in content:
                            numbered_list_found = True
                
                    if block_type == "todo":
                        checked = props.get("checked", False)
                        if not checked:
                            for expected in expected_todos:
                                if expected in content:
                                    todos_found += 1
                                    break
                
                    if block_type == "quote":
                        if "Good user stories are the foundation of great products" in content:
                            quote_found = True
            
                if not analysis_heading_found:
                    missing.append("heading_3 '🔍 User Story Analysis' between Parts 2 and 3")
                if not analysis_callout_found:
                    missing.append("yellow callout with 📊 icon and analysis text")
                if not numbered_list_found:
                    missing.append("numbered list with analysis counts")
                if not checklist_heading_found:
                    missing.append("heading_3 '✅ User Story Checklist'")
                if todos_found < 5:
                    missing.append(f"5 unchecked todos (found {todos_found})")
                if not quote_found:
                    missing.append("quote block with user stories foundation text")
        
            if missing:
                errors.append(f"[X] User Story Analysis is missing: {', '.join(missing)}")
            else:
                checks_passed.append(f"[C] User Story Analysis is has")
        
            return TaskScore(
                score=1.0 if len(errors) == 0 else 0.0,
                metadata=ScoreMetadata(
                    success_accumulator=list(dict.fromkeys(checks_passed)),
                    error_accumulator=list(dict.fromkeys(errors)),
                )
            )
    
        except Exception as e:
            errors.append(f"[X] Error validating user story analysis: {str(e)}")
            return TaskScore(
                score=0.0,
                metadata=ScoreMetadata(
                    success_accumulator=list(dict.fromkeys(checks_passed)),
                    error_accumulator=list(dict.fromkeys(errors)),
                )
            )

    # -----------------------------------------------------------------------------
    # add-sprint-metrics-kpis-v2
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_add_sprint_metrics_kpis(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validates the Sprint Metrics & KPIs section added to Sprint Planning page.
    
    Requirements:
    1. New section positioned between Sprint Goals and Action Items
    2. heading2 '📊 Sprint Metrics & KPIs'
    3. Green callout with '🎯' icon and velocity target text
    4. heading3 '📈 Team Capacity' with numbered list of team members
    5. Divider followed by heading3 '⚡ Sprint Risks'
    6. Three unchecked todos with color emoji indicators
    7. Existing checked todos in Action Items now start with '✅ DONE: '
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    try:
        try:
            # Find Sprint Planning page
            sprint_pages = _get_pages(backend, "Sprint Planning - Jan 15")
            if not sprint_pages:
                errors.append("[X] Sprint Planning - Jan 15 page not found")
            else:
                checks_passed.append("[C] Sprint Planning - Jan 15 page found")
        
            page = sprint_pages[0]
            page_id = page.get("_id")
            blocks = _get_blocks(backend, page_id)
        
            if not blocks:
                errors.append("[X] Sprint Planning page has no blocks")
            else:
                checks_passed.append("[C] Sprint Planning page has blocks")
        
            missing = []
        
            # Find Sprint Goals and Action Items positions
            sprint_goals_index = None
            action_items_index = None
        
            for i, block in enumerate(blocks):
                content = block.get("content", "")
                if block.get("type") == "heading2":
                    if "Sprint Goals" in content:
                        sprint_goals_index = i
                    elif "Action Items" in content:
                        action_items_index = i
        
            if sprint_goals_index is None:
                missing.append("Sprint Goals heading not found")
            if action_items_index is None:
                missing.append("Action Items heading not found")
        
            # Check for new content between Sprint Goals section and Action Items
            if sprint_goals_index is not None and action_items_index is not None:
                # Find where Sprint Goals content ends (numbered list items)
                # The new section should be after the last numbered list in Sprint Goals
            
                metrics_heading_found = False
                green_callout_found = False
                capacity_heading_found = False
                team_capacity_list = []
                divider_found = False
                risks_heading_found = False
                risk_todos_found = 0
            
                for i in range(sprint_goals_index + 1, action_items_index):
                    block = blocks[i]
                    block_type = block.get("type", "")
                    content = block.get("content", "")
                    props = block.get("properties", {})
                
                    if block_type == "heading2":
                        if "Sprint Metrics" in content or "KPIs" in content:
                            metrics_heading_found = True
                
                    if block_type == "callout":
                        if props.get("backgroundColor") == "green_background":
                            if props.get("icon") == "🎯" and "45 story points" in content:
                                green_callout_found = True
                
                    if block_type == "heading3":
                        if "Team Capacity" in content:
                            capacity_heading_found = True
                        elif "Sprint Risks" in content:
                            risks_heading_found = True
                
                    if block_type == "numberedList":
                        if "Alice:" in content and "15" in content:
                            team_capacity_list.append("Alice")
                        elif "Bob:" in content and "20" in content:
                            team_capacity_list.append("Bob")
                        elif "Carol:" in content and "10" in content:
                            team_capacity_list.append("Carol")
                
                    if block_type == "divider":
                        divider_found = True
                
                    if block_type == "todo":
                        checked = props.get("checked", False)
                        if not checked:
                            if "🔴" in content or "🟡" in content or "🔵" in content:
                                risk_todos_found += 1
            
                if not metrics_heading_found:
                    missing.append("heading2 '📊 Sprint Metrics & KPIs'")
                if not green_callout_found:
                    missing.append("green callout with 🎯 icon and velocity target")
                if not capacity_heading_found:
                    missing.append("heading3 '📈 Team Capacity'")
                if len(team_capacity_list) < 3:
                    missing.append(f"team capacity list (found {len(team_capacity_list)}/3)")
                if not divider_found:
                    missing.append("divider block")
                if not risks_heading_found:
                    missing.append("heading3 '⚡ Sprint Risks'")
                if risk_todos_found < 3:
                    missing.append(f"3 risk todos with color emojis (found {risk_todos_found})")
        
            # Check that existing checked todos have '✅ DONE: ' prefix
            done_prefix_count = 0
            for i in range(action_items_index + 1 if action_items_index else 0, len(blocks)):
                block = blocks[i]
                if block.get("type") == "todo":
                    props = block.get("properties", {})
                    content = block.get("content", "")
                    if props.get("checked", False):
                        if content.startswith("✅ DONE:"):
                            done_prefix_count += 1
        
            if done_prefix_count < 2:
                missing.append(f"checked todos with '✅ DONE: ' prefix (found {done_prefix_count}/2)")
        
            if missing:
                errors.append(f"[X] Sprint Metrics KPIs is missing: {', '.join(missing)}")
            else:
                checks_passed.append(f"[C] Sprint Metrics KPIs is has")
        
            return TaskScore(
                score=1.0 if len(errors) == 0 else 0.0,
                metadata=ScoreMetadata(
                    success_accumulator=list(dict.fromkeys(checks_passed)),
                    error_accumulator=list(dict.fromkeys(errors)),
                )
            )
    
        except Exception as e:
            errors.append(f"[X] Error validating sprint metrics KPIs: {str(e)}")
            return TaskScore(
                score=0.0,
                metadata=ScoreMetadata(
                    success_accumulator=list(dict.fromkeys(checks_passed)),
                    error_accumulator=list(dict.fromkeys(errors)),
                )
            )

    # -----------------------------------------------------------------------------
    # complex-handbook-reorganization-v2
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_complex_handbook_reorganization(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validates the complex reorganization of the Company Handbook page.
    
    Requirements:
    1. Benefits section appears where Our Values was (after intro paragraph)
    2. Our Values section appears where Benefits was (at the end)
    3. New Company Culture section between Benefits and Work Policies
    4. Bookmark after Remote Work heading but before its paragraph
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    try:
        try:
            # Find Company Handbook page
            handbook_pages = _get_pages(backend, "Company Handbook")
            if not handbook_pages:
                errors.append("[X] Company Handbook page not found")
            else:
                checks_passed.append("[C] Company Handbook page found")
        
            page = handbook_pages[0]
            page_id = page.get("_id")
            blocks = _get_blocks(backend, page_id)
        
            if not blocks:
                errors.append("[X] Company Handbook page has no blocks")
            else:
                checks_passed.append("[C] Company Handbook page has blocks")
        
            missing = []
        
            # Find section positions
            benefits_index = None
            our_values_index = None
            work_policies_index = None
            company_culture_index = None
            remote_work_index = None
        
            for i, block in enumerate(blocks):
                content = block.get("content", "")
                block_type = block.get("type", "")
            
                if block_type == "heading2":
                    if "Benefits" in content:
                        benefits_index = i
                    elif "Our Values" in content:
                        our_values_index = i
                    elif "Work Policies" in content:
                        work_policies_index = i
                    elif "Company Culture" in content:
                        company_culture_index = i
                elif block_type == "heading3":
                    if "Remote Work" in content:
                        remote_work_index = i
        
            # Check Benefits appears before Work Policies (should be early in the page)
            if benefits_index is None:
                missing.append("Benefits heading2 not found")
            elif work_policies_index is not None and benefits_index > work_policies_index:
                missing.append("Benefits section should appear before Work Policies")
        
            # Check Company Culture exists between Benefits and Work Policies
            if company_culture_index is None:
                missing.append("Company Culture heading2 not found")
            elif benefits_index is not None and work_policies_index is not None:
                if not (benefits_index < company_culture_index < work_policies_index):
                    missing.append("Company Culture should be between Benefits and Work Policies")
        
            # Check Our Values appears after Work Policies (at the end)
            if our_values_index is None:
                missing.append("Our Values heading2 not found")
            elif work_policies_index is not None and our_values_index < work_policies_index:
                missing.append("Our Values section should appear after Work Policies (swapped to end)")
        
            # Check Company Culture content
            if company_culture_index is not None:
                # Look for callout and bullets after Company Culture heading
                callout_found = False
                culture_bullets = 0
            
                for i in range(company_culture_index + 1, min(company_culture_index + 6, len(blocks))):
                    block = blocks[i]
                    block_type = block.get("type", "")
                    content = block.get("content", "")
                    props = block.get("properties", {})
                
                    if block_type == "heading2":  # Hit next section
                        break
                
                    if block_type == "callout":
                        if props.get("backgroundColor") == "green_background":
                            if props.get("icon") == "🎯" and "culture drives everything" in content:
                                callout_found = True
                
                    if block_type == "bulletedList":
                        if "Innovation" in content or "Integrity" in content or "Impact" in content:
                            culture_bullets += 1
            
                if not callout_found:
                    missing.append("Company Culture callout with green background and 🎯 icon")
                if culture_bullets < 3:
                    missing.append(f"Company Culture needs 3 bullets (found {culture_bullets})")
        
            # Check bookmark after Remote Work heading
            if remote_work_index is not None:
                bookmark_found = False
                # Check if next block is a bookmark
                if remote_work_index + 1 < len(blocks):
                    next_block = blocks[remote_work_index + 1]
                    if next_block.get("type") == "bookmark":
                        props = next_block.get("properties", {})
                        url = props.get("url", "")
                        if "remote" in url.lower() and "policies" in url.lower():
                            bookmark_found = True
            
                if not bookmark_found:
                    missing.append("bookmark after Remote Work heading")
        
            # Count Benefits numbered items (should be 4)
            if benefits_index is not None:
                benefits_items = 0
                for i in range(benefits_index + 1, len(blocks)):
                    block = blocks[i]
                    if block.get("type") == "heading2":
                        break
                    if block.get("type") == "numberedList":
                        benefits_items += 1
                if benefits_items < 4:
                    missing.append(f"Benefits section needs 4 numbered items (found {benefits_items})")
        
            # Count Our Values bullet items (should be 3)
            if our_values_index is not None:
                values_items = 0
                for i in range(our_values_index + 1, len(blocks)):
                    block = blocks[i]
                    if block.get("type") == "heading2":
                        break
                    if block.get("type") == "bulletedList":
                        values_items += 1
                if values_items < 3:
                    missing.append(f"Our Values section needs 3 bullets (found {values_items})")
        
            if missing:
                errors.append(f"[X] Complex handbook reorganization is missing: {', '.join(missing)}")
            else:
                checks_passed.append(f"[C] Complex handbook reorganization is has")
        
            return TaskScore(
                score=1.0 if len(errors) == 0 else 0.0,
                metadata=ScoreMetadata(
                    success_accumulator=list(dict.fromkeys(checks_passed)),
                    error_accumulator=list(dict.fromkeys(errors)),
                )
            )
    
        except Exception as e:
            errors.append(f"[X] Error validating complex handbook reorganization: {str(e)}")
            return TaskScore(
                score=0.0,
                metadata=ScoreMetadata(
                    success_accumulator=list(dict.fromkeys(checks_passed)),
                    error_accumulator=list(dict.fromkeys(errors)),
                )
            )

    # -----------------------------------------------------------------------------
    # cross-page-values-integration-v2
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_cross_page_values_integration(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validates cross-page values integration from Company Handbook to Team Directory.
    
    Requirements:
    1. Team Directory has 'Living Our Values' section after title
    2. Three callouts with blue/green/purple backgrounds and 💎 icon
    3. Callouts contain the exact value texts from Company Handbook
    4. Team Commitment section with 3 numbered list items
    5. Divider followed by Quick Links section
    6. Bookmark to Company Handbook
    7. Unchecked todo for values review
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    try:
        try:
            # Find Team Directory page
            team_pages = _get_pages(backend, "Team Directory")
            if not team_pages:
                errors.append("[X] Team Directory page not found")
            else:
                checks_passed.append("[C] Team Directory page found")
        
            page = team_pages[0]
            page_id = page.get("_id")
            blocks = _get_blocks(backend, page_id)
        
            if not blocks:
                errors.append("[X] Team Directory page has no blocks")
            else:
                checks_passed.append("[C] Team Directory page has blocks")
        
            missing = []
        
            # Expected values from Company Handbook
            expected_values = [
                "Customer First",
                "Excellence",
                "Collaboration"
            ]
        
            # Check for Living Our Values heading
            living_values_index = None
            for i, block in enumerate(blocks):
                if block.get("type") == "heading2":
                    if "Living Our Values" in block.get("content", ""):
                        living_values_index = i
                        break
        
            if living_values_index is None:
                missing.append("heading2 'Living Our Values'")
        
            # Check for intro paragraph
            intro_found = False
            for block in blocks:
                if block.get("type") == "paragraph":
                    if "core values" in block.get("content", "").lower():
                        intro_found = True
                        break
        
            if not intro_found:
                missing.append("intro paragraph about core values")
        
            # Check for 3 callouts with correct colors
            callouts = []
            for block in blocks:
                if block.get("type") == "callout":
                    props = block.get("properties", {})
                    bg = props.get("backgroundColor", "")
                    icon = props.get("icon", "")
                    content = block.get("content", "")
                    if icon == "💎":
                        callouts.append({
                            "bg": bg,
                            "content": content
                        })
        
            # Check colors (blue, green, purple)
            expected_colors = ["blue_background", "green_background", "purple_background"]
            callout_colors = [c["bg"] for c in callouts]
        
            for color in expected_colors:
                if color not in callout_colors:
                    missing.append(f"callout with {color}")
        
            # Check callout contents contain value keywords
            callout_contents = " ".join([c["content"] for c in callouts])
            for value in expected_values:
                if value not in callout_contents:
                    missing.append(f"callout containing '{value}'")
        
            # Check for Team Commitment heading
            commitment_found = False
            for block in blocks:
                if block.get("type") == "heading3":
                    if "Team Commitment" in block.get("content", ""):
                        commitment_found = True
                        break
        
            if not commitment_found:
                missing.append("heading3 'Team Commitment'")
        
            # Check for numbered list items referencing values
            numbered_items = [b for b in blocks if b.get("type") == "numberedList"]
            if len(numbered_items) < 3:
                missing.append(f"3 numbered list items (found {len(numbered_items)})")
            else:
                numbered_content = " ".join([b.get("content", "") for b in numbered_items])
                for value in expected_values:
                    if value not in numbered_content:
                        missing.append(f"numbered item referencing '{value}'")
        
            # Check for divider
            divider_found = any(b.get("type") == "divider" for b in blocks)
            if not divider_found:
                missing.append("divider block")
        
            # Check for Quick Links heading
            quick_links_found = False
            for block in blocks:
                if block.get("type") == "heading2":
                    if "Quick Links" in block.get("content", ""):
                        quick_links_found = True
                        break
        
            if not quick_links_found:
                missing.append("heading2 'Quick Links'")
        
            # Check for bookmark
            bookmark_found = False
            for block in blocks:
                if block.get("type") == "bookmark":
                    props = block.get("properties", {})
                    url = props.get("url", "")
                    if "handbook" in url.lower() or "company" in url.lower():
                        bookmark_found = True
                        break
        
            if not bookmark_found:
                missing.append("bookmark to Company Handbook")
        
            # Check for unchecked todo about values review
            todo_found = False
            for block in blocks:
                if block.get("type") == "todo":
                    props = block.get("properties", {})
                    content = block.get("content", "")
                    if not props.get("checked", False):
                        if "values review" in content.lower() or "quarterly" in content.lower():
                            todo_found = True
                            break
        
            if not todo_found:
                missing.append("unchecked todo for values review")
        
            if missing:
                errors.append(f"[X] Cross-page values integration is missing: {', '.join(missing)}")
            else:
                checks_passed.append(f"[C] Cross-page values integration is has")
        
            return TaskScore(
                score=1.0 if len(errors) == 0 else 0.0,
                metadata=ScoreMetadata(
                    success_accumulator=list(dict.fromkeys(checks_passed)),
                    error_accumulator=list(dict.fromkeys(errors)),
                )
            )
    
        except Exception as e:
            errors.append(f"[X] Error validating cross-page values integration: {str(e)}")
            return TaskScore(
                score=0.0,
                metadata=ScoreMetadata(
                    success_accumulator=list(dict.fromkeys(checks_passed)),
                    error_accumulator=list(dict.fromkeys(errors)),
                )
            )

    # -----------------------------------------------------------------------------
    # add-medium-priority-stats-v2
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_add_medium_priority_stats(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validates the addition of completion stats to Bug Tracker's Medium Priority section.
    
    Requirements:
    1. Orange callout between Medium Priority heading and first todo
    2. Callout shows accurate completion rate (1/2 = 50%)
    3. Divider after all Medium Priority todos
    4. Paragraph with today's date after divider
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    try:
        try:
            # Find Bug Tracker page
            bug_pages = _get_pages(backend, "Bug Tracker")
            if not bug_pages:
                errors.append("[X] Bug Tracker page not found")
            else:
                checks_passed.append("[C] Bug Tracker page found")
        
            page = bug_pages[0]
            page_id = page.get("_id")
            blocks = _get_blocks(backend, page_id)
        
            if not blocks:
                errors.append("[X] Bug Tracker page has no blocks")
            else:
                checks_passed.append("[C] Bug Tracker page has blocks")
        
            missing = []
        
            # Find Medium Priority and Low Priority heading positions
            medium_priority_index = None
            low_priority_index = None
        
            for i, block in enumerate(blocks):
                if block.get("type") == "heading2":
                    content = block.get("content", "")
                    if "Medium Priority" in content:
                        medium_priority_index = i
                    elif "Low Priority" in content:
                        low_priority_index = i
        
            if medium_priority_index is None:
                missing.append("Medium Priority heading not found")
            if low_priority_index is None:
                missing.append("Low Priority heading not found")
        
            if medium_priority_index is not None and low_priority_index is not None:
                # Check for orange callout immediately after Medium Priority heading
                callout_found = False
                callout_index = None
            
                for i in range(medium_priority_index + 1, low_priority_index):
                    block = blocks[i]
                    if block.get("type") == "callout":
                        props = block.get("properties", {})
                        if props.get("backgroundColor") == "orange_background":
                            if props.get("icon") == "📊":
                                content = block.get("content", "")
                                # Check for completion rate pattern
                                if "Completion rate" in content and "%" in content:
                                    # Verify it contains correct numbers (1 out of 2, 50%)
                                    if ("1" in content and "2" in content and "50" in content):
                                        callout_found = True
                                        callout_index = i
                                        break
            
                if not callout_found:
                    missing.append("orange callout with 📊 icon and correct completion rate (1 out of 2, 50%)")
                elif callout_index is not None:
                    # Verify callout is right after Medium Priority heading
                    if callout_index != medium_priority_index + 1:
                        missing.append("callout not immediately after Medium Priority heading")
            
                # Check for divider before Low Priority
                divider_found = False
                paragraph_found = False
            
                for i in range(medium_priority_index + 1, low_priority_index):
                    block = blocks[i]
                    if block.get("type") == "divider":
                        divider_found = True
                    if block.get("type") == "paragraph":
                        content = block.get("content", "")
                        if "Last reviewed" in content or "reviewed" in content.lower():
                            # Check for date pattern (various formats accepted)
                            import re
                            date_pattern = r'\d{1,4}[-/]\d{1,2}[-/]\d{1,4}|\w+ \d{1,2},? \d{4}|\d{1,2} \w+ \d{4}'
                            if re.search(date_pattern, content):
                                paragraph_found = True
            
                if not divider_found:
                    missing.append("divider after Medium Priority todos")
                if not paragraph_found:
                    missing.append("paragraph with 'Last reviewed' and date")
        
            if missing:
                errors.append(f"[X] Medium Priority stats is missing: {', '.join(missing)}")
            else:
                checks_passed.append(f"[C] Medium Priority stats is has")
        
            return TaskScore(
                score=1.0 if len(errors) == 0 else 0.0,
                metadata=ScoreMetadata(
                    success_accumulator=list(dict.fromkeys(checks_passed)),
                    error_accumulator=list(dict.fromkeys(errors)),
                )
            )
    
        except Exception as e:
            errors.append(f"[X] Error validating medium priority stats: {str(e)}")
            return TaskScore(
                score=0.0,
                metadata=ScoreMetadata(
                    success_accumulator=list(dict.fromkeys(checks_passed)),
                    error_accumulator=list(dict.fromkeys(errors)),
                )
            )

    # -----------------------------------------------------------------------------
    # add-handbook-update-tracking-v2
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_add_handbook_update_tracking(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validates the addition of update tracking system to Company Handbook.
    
    Requirements:
    1. heading2 '📝 Recent Updates & Changes' at top after title
    2. Blue callout with 🔄 icon and today's date
    3. heading3 '🕐 Update History' with 3 numbered list items
    4. Divider
    5. heading3 '⚠️ Pending Reviews' with 3 unchecked todos
    6. Quote block at end of new section
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    try:
        try:
            # Find Company Handbook page
            handbook_pages = _get_pages(backend, "Company Handbook")
            if not handbook_pages:
                errors.append("[X] Company Handbook page not found")
            else:
                checks_passed.append("[C] Company Handbook page found")
        
            page = handbook_pages[0]
            page_id = page.get("_id")
            blocks = _get_blocks(backend, page_id)
        
            if not blocks:
                errors.append("[X] Company Handbook page has no blocks")
            else:
                checks_passed.append("[C] Company Handbook page has blocks")
        
            missing = []
        
            # Find the new section (should start after title)
            recent_updates_idx = None
            for i, block in enumerate(blocks):
                if block.get("type") == "heading2" and "Recent Updates" in block.get("content", ""):
                    recent_updates_idx = i
                    break
        
            if recent_updates_idx is None:
                missing.append("heading2 '📝 Recent Updates & Changes'")
            else:
                # Check it's near the top (after title)
                if recent_updates_idx > 2:
                    missing.append("Recent Updates heading should be near the top after title")
        
            # Check for blue callout with 🔄 icon
            callout_found = False
            for block in blocks:
                if block.get("type") == "callout":
                    props = block.get("properties", {})
                    content = block.get("content", "")
                    if (props.get("backgroundColor") == "blue_background" and 
                        props.get("icon") == "🔄" and
                        "reviewed" in content.lower()):
                        callout_found = True
                        break
        
            if not callout_found:
                missing.append("blue callout with 🔄 icon about handbook review date")
        
            # Check for Update History heading
            update_history_found = False
            for block in blocks:
                if block.get("type") == "heading3" and "Update History" in block.get("content", ""):
                    update_history_found = True
                    break
        
            if not update_history_found:
                missing.append("heading3 '🕐 Update History'")
        
            # Check for numbered list items (at least 3)
            numbered_items = [b for b in blocks if b.get("type") == "numberedList"]
            if len(numbered_items) < 3:
                missing.append(f"at least 3 numbered list items (found {len(numbered_items)})")
        
            # Check for divider
            divider_found = any(b.get("type") == "divider" for b in blocks)
            if not divider_found:
                missing.append("divider block")
        
            # Check for Pending Reviews heading
            pending_reviews_found = False
            for block in blocks:
                if block.get("type") == "heading3" and "Pending Reviews" in block.get("content", ""):
                    pending_reviews_found = True
                    break
        
            if not pending_reviews_found:
                missing.append("heading3 '⚠️ Pending Reviews'")
        
            # Check for 3 unchecked todo blocks with due dates
            unchecked_todos = [b for b in blocks if b.get("type") == "todo" and 
                              not b.get("properties", {}).get("checked", False) and
                              "Due" in b.get("content", "")]
            if len(unchecked_todos) < 3:
                missing.append(f"3 unchecked todo blocks with due dates (found {len(unchecked_todos)})")
        
            # Check for quote block
            quote_found = False
            for block in blocks:
                if block.get("type") == "quote":
                    content = block.get("content", "")
                    if "culture" in content.lower() or "values" in content.lower():
                        quote_found = True
                        break
        
            if not quote_found:
                missing.append("quote block about culture and values")
        
            if missing:
                errors.append(f"[X] Handbook update tracking is missing: {', '.join(missing)}")
            else:
                checks_passed.append(f"[C] Handbook update tracking is has")
        
            return TaskScore(
                score=1.0 if len(errors) == 0 else 0.0,
                metadata=ScoreMetadata(
                    success_accumulator=list(dict.fromkeys(checks_passed)),
                    error_accumulator=list(dict.fromkeys(errors)),
                )
            )
    
        except Exception as e:
            errors.append(f"[X] Error validating handbook update tracking: {str(e)}")
            return TaskScore(
                score=0.0,
                metadata=ScoreMetadata(
                    success_accumulator=list(dict.fromkeys(checks_passed)),
                    error_accumulator=list(dict.fromkeys(errors)),
                )
            )

    # -----------------------------------------------------------------------------
    # add-team-velocity-tracker-v2
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_add_team_velocity_tracker(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validates the addition of team velocity tracker to Weekly Standup Template.
    
    Requirements:
    1. heading_2 '📈 Team Velocity Tracker' at end of page
    2. paragraph 'Track weekly progress and identify bottlenecks.'
    3. heading_3 'Week of January 29, 2024'
    4. Four callouts with specific colors and icons:
       - blue + 📝 + Planned: 15 story points
       - green + ✅ + Completed: 12 story points
       - orange + ⏰ + Velocity: 80%
       - purple + 💡 + Insight: Focus on reducing scope
    5. divider at end
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    try:
        try:
            # Find Weekly Standup Template page
            standup_pages = _get_pages(backend, "Weekly Standup Template")
            if not standup_pages:
                errors.append("[X] Weekly Standup Template page not found")
            else:
                checks_passed.append("[C] Weekly Standup Template page found")
        
            page = standup_pages[0]
            page_id = page.get("_id")
            blocks = _get_blocks(backend, page_id)
        
            if not blocks:
                errors.append("[X] Weekly Standup Template page has no blocks")
            else:
                checks_passed.append("[C] Weekly Standup Template page has blocks")
        
            missing = []
        
            # Check for Team Velocity Tracker heading
            velocity_heading_found = False
            for block in blocks:
                if block.get("type") == "heading2" and "Team Velocity Tracker" in block.get("content", ""):
                    velocity_heading_found = True
                    break
        
            if not velocity_heading_found:
                missing.append("heading_2 '📈 Team Velocity Tracker'")
        
            # Check for tracking paragraph
            tracking_para_found = False
            for block in blocks:
                if block.get("type") == "paragraph":
                    content = block.get("content", "")
                    if "Track weekly progress" in content and "bottlenecks" in content:
                        tracking_para_found = True
                        break
        
            if not tracking_para_found:
                missing.append("paragraph about tracking progress and bottlenecks")
        
            # Check for Week heading
            week_heading_found = False
            for block in blocks:
                if block.get("type") == "heading3" and "Week of" in block.get("content", ""):
                    week_heading_found = True
                    break
        
            if not week_heading_found:
                missing.append("heading_3 'Week of January 29, 2024'")
        
            # Check for four callouts with correct colors
            callouts = [b for b in blocks if b.get("type") == "callout"]
        
            # Check blue callout (Planned)
            blue_found = False
            for c in callouts:
                props = c.get("properties", {})
                if props.get("backgroundColor") == "blue_background" and "Planned" in c.get("content", ""):
                    if props.get("icon") == "📝":
                        blue_found = True
                        break
        
            if not blue_found:
                missing.append("blue callout with 📝 icon for Planned story points")
        
            # Check green callout (Completed)
            green_found = False
            for c in callouts:
                props = c.get("properties", {})
                if props.get("backgroundColor") == "green_background" and "Completed" in c.get("content", ""):
                    if props.get("icon") == "✅":
                        green_found = True
                        break
        
            if not green_found:
                missing.append("green callout with ✅ icon for Completed story points")
        
            # Check orange callout (Velocity)
            orange_found = False
            for c in callouts:
                props = c.get("properties", {})
                if props.get("backgroundColor") == "orange_background" and "Velocity" in c.get("content", ""):
                    if props.get("icon") == "⏰":
                        orange_found = True
                        break
        
            if not orange_found:
                missing.append("orange callout with ⏰ icon for Velocity percentage")
        
            # Check purple callout (Insight)
            purple_found = False
            for c in callouts:
                props = c.get("properties", {})
                if props.get("backgroundColor") == "purple_background" and "Insight" in c.get("content", ""):
                    if props.get("icon") == "💡":
                        purple_found = True
                        break
        
            if not purple_found:
                missing.append("purple callout with 💡 icon for Insight")
        
            # Check for divider at end
            divider_found = any(b.get("type") == "divider" for b in blocks)
            if not divider_found:
                missing.append("divider at end of section")
        
            if missing:
                errors.append(f"[X] Team Velocity Tracker is missing: {', '.join(missing)}")
            else:
                checks_passed.append(f"[C] Team Velocity Tracker is has")
        
            return TaskScore(
                score=1.0 if len(errors) == 0 else 0.0,
                metadata=ScoreMetadata(
                    success_accumulator=list(dict.fromkeys(checks_passed)),
                    error_accumulator=list(dict.fromkeys(errors)),
                )
            )
    
        except Exception as e:
            errors.append(f"[X] Error validating team velocity tracker: {str(e)}")
            return TaskScore(
                score=0.0,
                metadata=ScoreMetadata(
                    success_accumulator=list(dict.fromkeys(checks_passed)),
                    error_accumulator=list(dict.fromkeys(errors)),
                )
            )

    # -----------------------------------------------------------------------------
    # create-goals-dashboard-v2
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_create_goals_dashboard(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validates the creation of 2024 Goals Dashboard.
    
    Requirements:
    1. Page titled '🎯 2024 Goals Dashboard' exists
    2. heading1 with dashboard title
    3. Green callout with 📊 icon and executive summary
    4. For each goals page: heading2, quote with progress stats, numbered list
    5. Final heading2 '🏆 Completed Objectives' with bulleted items
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    try:
        try:
            # Find the dashboard page
            dashboard_pages = _get_pages(backend, "2024 Goals Dashboard")
            if not dashboard_pages:
                errors.append("[X] 2024 Goals Dashboard page not found")
            else:
                checks_passed.append("[C] 2024 Goals Dashboard page found")
        
            page = dashboard_pages[0]
            page_id = page.get("_id")
            blocks = _get_blocks(backend, page_id)
        
            if not blocks:
                errors.append("[X] 2024 Goals Dashboard page has no blocks")
            else:
                checks_passed.append("[C] 2024 Goals Dashboard page has blocks")
        
            missing = []
        
            # Check for heading1 with dashboard title
            title_found = False
            for block in blocks:
                if block.get("type") == "heading1" and "2024 Goals Dashboard" in block.get("content", ""):
                    title_found = True
                    break
        
            if not title_found:
                missing.append("heading1 '🎯 2024 Goals Dashboard'")
        
            # Check for green callout with executive summary
            summary_callout_found = False
            for block in blocks:
                if block.get("type") == "callout":
                    props = block.get("properties", {})
                    content = block.get("content", "")
                    if (props.get("backgroundColor") == "green_background" and
                        props.get("icon") == "📊" and
                        "Executive Summary" in content):
                        summary_callout_found = True
                        break
        
            if not summary_callout_found:
                missing.append("green callout with 📊 icon and 'Executive Summary'")
        
            # Check for page section headings (heading2 with 📁)
            page_headings = [b for b in blocks if b.get("type") == "heading2" and "📁" in b.get("content", "")]
            if len(page_headings) == 0:
                missing.append("heading2 sections for goals pages (with 📁 prefix)")
        
            # Check for quote blocks with progress format
            progress_quotes = [b for b in blocks if b.get("type") == "quote" and "Progress:" in b.get("content", "")]
            if len(progress_quotes) == 0:
                missing.append("quote blocks with 'Progress: X of Y objectives completed' format")
        
            # Check for numbered list items (unchecked todos)
            numbered_items = [b for b in blocks if b.get("type") == "numberedList"]
            # There should be some numbered items if there are unchecked todos
        
            # Check for Completed Objectives heading
            completed_heading_found = False
            for block in blocks:
                if block.get("type") == "heading2" and "Completed Objectives" in block.get("content", ""):
                    completed_heading_found = True
                    break
        
            if not completed_heading_found:
                missing.append("heading2 '🏆 Completed Objectives'")
        
            # Check for bulleted list items (completed todos)
            bulleted_items = [b for b in blocks if b.get("type") == "bulletedList"]
            # Should have some if there are checked todos
        
            if missing:
                errors.append(f"[X] Goals Dashboard is missing: {', '.join(missing)}")
            else:
                checks_passed.append(f"[C] Goals Dashboard is has")
        
            return TaskScore(
                score=1.0 if len(errors) == 0 else 0.0,
                metadata=ScoreMetadata(
                    success_accumulator=list(dict.fromkeys(checks_passed)),
                    error_accumulator=list(dict.fromkeys(errors)),
                )
            )
    
        except Exception as e:
            errors.append(f"[X] Error validating goals dashboard: {str(e)}")
            return TaskScore(
                score=0.0,
                metadata=ScoreMetadata(
                    success_accumulator=list(dict.fromkeys(checks_passed)),
                    error_accumulator=list(dict.fromkeys(errors)),
                )
            )

    # -----------------------------------------------------------------------------
    # add-checklist-analysis-v2
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_add_checklist_analysis(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validates the checklist analysis additions on Getting Started page.
    
    Requirements:
    1. Blue callout with progress stats after Quick Start Checklist heading
    2. Each unchecked todo followed by 3 numbered sub-items
    3. Completion Rewards section between checklist and Key Features
    4. Conditional green callout if >50% todos checked
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    try:
        try:
            # Find Getting Started page
            pages = _get_pages(backend, "Getting Started")
            if not pages:
                errors.append("[X] Getting Started page not found")
            else:
                checks_passed.append("[C] Getting Started page found")
        
            page = pages[0]
            page_id = page.get("_id")
            blocks = _get_blocks(backend, page_id)
        
            if not blocks:
                errors.append("[X] Getting Started page has no blocks")
            else:
                checks_passed.append("[C] Getting Started page has blocks")
        
            missing = []
        
            # Count todos for validation
            todos = [b for b in blocks if b.get("type") == "todo"]
            checked_count = sum(1 for t in todos if t.get("properties", {}).get("checked", False))
            total_count = len(todos)
        
            # Check for blue progress callout
            progress_callout_found = False
            for block in blocks:
                if block.get("type") == "callout":
                    props = block.get("properties", {})
                    content = block.get("content", "")
                    if (props.get("backgroundColor") == "blue_background" and
                        props.get("icon") == "📊" and
                        "Progress" in content):
                        progress_callout_found = True
                        break
        
            if not progress_callout_found:
                missing.append("blue progress callout with 📊 icon after Quick Start Checklist heading")
        
            # Check for numbered sub-items (should have multiples of 3 if unchecked todos exist)
            numbered_items = [b for b in blocks if b.get("type") == "numberedList"]
            unchecked_todos = total_count - checked_count
        
            # Check for sub-task text patterns
            time_items = [n for n in numbered_items if "Estimated time" in n.get("content", "")]
            difficulty_items = [n for n in numbered_items if "Difficulty" in n.get("content", "")]
            prereq_items = [n for n in numbered_items if "Prerequisites" in n.get("content", "")]
        
            if unchecked_todos > 0:
                if len(time_items) < unchecked_todos:
                    missing.append(f"numbered 'Estimated time' items (need {unchecked_todos}, found {len(time_items)})")
                if len(difficulty_items) < unchecked_todos:
                    missing.append(f"numbered 'Difficulty' items (need {unchecked_todos}, found {len(difficulty_items)})")
                if len(prereq_items) < unchecked_todos:
                    missing.append(f"numbered 'Prerequisites' items (need {unchecked_todos}, found {len(prereq_items)})")
        
            # Check for Completion Rewards heading
            rewards_heading_found = False
            for block in blocks:
                if block.get("type") == "heading2" and "Completion Rewards" in block.get("content", ""):
                    rewards_heading_found = True
                    break
        
            if not rewards_heading_found:
                missing.append("heading2 '🎯 Completion Rewards'")
        
            # Check for rewards bulleted items
            bullet_items = [b for b in blocks if b.get("type") == "bulletedList"]
            rewards_bullets = [
                any("50%" in b.get("content", "") and "advanced templates" in b.get("content", "").lower() for b in bullet_items),
                any("75%" in b.get("content", "") and "priority support" in b.get("content", "").lower() for b in bullet_items),
                any("100%" in b.get("content", "") and "power user" in b.get("content", "").lower() for b in bullet_items)
            ]
        
            if not all(rewards_bullets):
                missing.append("bulleted rewards list (50%, 75%, 100% milestones)")
        
            # Check for conditional green callout (only if >50% checked)
            if total_count > 0 and (checked_count / total_count) > 0.5:
                green_callout_found = False
                for block in blocks:
                    if block.get("type") == "callout":
                        props = block.get("properties", {})
                        content = block.get("content", "")
                        if (props.get("backgroundColor") == "green_background" and
                            "Great progress" in content):
                            green_callout_found = True
                            break
            
                if not green_callout_found:
                    missing.append("green callout with 'Great progress' message (>50% complete)")
        
            if missing:
                errors.append(f"[X] Checklist analysis is missing: {', '.join(missing)}")
            else:
                checks_passed.append(f"[C] Checklist analysis is has")
        
            return TaskScore(
                score=1.0 if len(errors) == 0 else 0.0,
                metadata=ScoreMetadata(
                    success_accumulator=list(dict.fromkeys(checks_passed)),
                    error_accumulator=list(dict.fromkeys(errors)),
                )
            )
    
        except Exception as e:
            errors.append(f"[X] Error validating checklist analysis: {str(e)}")
            return TaskScore(
                score=0.0,
                metadata=ScoreMetadata(
                    success_accumulator=list(dict.fromkeys(checks_passed)),
                    error_accumulator=list(dict.fromkeys(errors)),
                )
            )

    # -----------------------------------------------------------------------------
    # create-team-productivity-report-v2
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_create_team_productivity_report(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validates the team productivity report creation.
    
    Requirements:
    1. Page titled 'Team Productivity Report' exists
    2. heading1 with report title
    3. Executive Summary with heading2 and paragraph
    4. 6 page sections with heading3 and task stats
    5. Key Insights section with numbered rankings
    6. Divider and timestamp at end
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    try:
        try:
            # Find the report page
            report_pages = _get_pages(backend, "Team Productivity Report")
            if not report_pages:
                errors.append("[X] Team Productivity Report page not found")
            else:
                checks_passed.append("[C] Team Productivity Report page found")
        
            page = report_pages[0]
            page_id = page.get("_id")
            blocks = _get_blocks(backend, page_id)
        
            if not blocks:
                errors.append("[X] Team Productivity Report page has no blocks")
            else:
                checks_passed.append("[C] Team Productivity Report page has blocks")
        
            missing = []
        
            # Check for heading1 with report title
            title_found = False
            for block in blocks:
                if block.get("type") == "heading1" and "Team Productivity Report" in block.get("content", ""):
                    title_found = True
                    break
        
            if not title_found:
                missing.append("heading1 '👥 Team Productivity Report'")
        
            # Check for Executive Summary heading
            summary_heading_found = False
            for block in blocks:
                if block.get("type") == "heading2" and "Executive Summary" in block.get("content", ""):
                    summary_heading_found = True
                    break
        
            if not summary_heading_found:
                missing.append("heading2 '📊 Executive Summary'")
        
            # Check for page sections (heading3 for each analyzed page)
            heading3_blocks = [b for b in blocks if b.get("type") == "heading3"]
            expected_pages = ["Getting Started", "Q1 Goals", "Q2 Goals", "Sprint Planning", "Bug Tracker", "Feature Requests"]
            found_pages = []
            for h3 in heading3_blocks:
                content = h3.get("content", "")
                for page_name in expected_pages:
                    if page_name in content:
                        found_pages.append(page_name)
                        break
        
            if len(found_pages) < 6:
                missing.append(f"heading3 sections for all 6 pages (found {len(found_pages)})")
        
            # Check for task stats in bulleted lists
            bullet_items = [b for b in blocks if b.get("type") == "bulletedList"]
            has_total = any("Total tasks" in b.get("content", "") for b in bullet_items)
            has_completed = any("Completed" in b.get("content", "") for b in bullet_items)
            has_pending = any("Pending" in b.get("content", "") for b in bullet_items)
            has_rate = any("Completion rate" in b.get("content", "") or "%" in b.get("content", "") for b in bullet_items)
        
            if not (has_total and has_completed and has_pending):
                missing.append("bulletedList items with task stats (Total/Completed/Pending)")
        
            # Check for Key Insights heading
            insights_heading_found = False
            for block in blocks:
                if block.get("type") == "heading2" and "Key Insights" in block.get("content", ""):
                    insights_heading_found = True
                    break
        
            if not insights_heading_found:
                missing.append("heading2 '🏆 Key Insights'")
        
            # Check for numbered list items (insights)
            numbered_items = [b for b in blocks if b.get("type") == "numberedList"]
            has_highest = any("Highest" in b.get("content", "") or "highest" in b.get("content", "") for b in numbered_items)
            has_most = any("Most" in b.get("content", "") or "most" in b.get("content", "") for b in numbered_items)
            has_attention = any("attention" in b.get("content", "").lower() or "lowest" in b.get("content", "").lower() for b in numbered_items)
        
            if not (has_highest and has_most and has_attention):
                missing.append("numbered insights (highest/most/needs attention)")
        
            # Check for divider
            divider_found = any(b.get("type") == "divider" for b in blocks)
            if not divider_found:
                missing.append("divider at end")
        
            # Check for timestamp paragraph
            timestamp_found = False
            import re
            for block in blocks:
                if block.get("type") == "paragraph":
                    content = block.get("content", "")
                    # Check for date-like patterns
                    if re.search(r'\d{4}|\d{1,2}[-/]\d{1,2}|generated|report|timestamp', content.lower()):
                        timestamp_found = True
                        break
        
            if not timestamp_found:
                missing.append("timestamp paragraph at end")
        
            if missing:
                errors.append(f"[X] Team Productivity Report is missing: {', '.join(missing)}")
            else:
                checks_passed.append(f"[C] Team Productivity Report is has")
        
            return TaskScore(
                score=1.0 if len(errors) == 0 else 0.0,
                metadata=ScoreMetadata(
                    success_accumulator=list(dict.fromkeys(checks_passed)),
                    error_accumulator=list(dict.fromkeys(errors)),
                )
            )
    
        except Exception as e:
            errors.append(f"[X] Error validating team productivity report: {str(e)}")
            return TaskScore(
                score=0.0,
                metadata=ScoreMetadata(
                    success_accumulator=list(dict.fromkeys(checks_passed)),
                    error_accumulator=list(dict.fromkeys(errors)),
                )
            )

    # -----------------------------------------------------------------------------
    # create-quarterly-health-report-v2
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_create_quarterly_health_report(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validates the quarterly project health report.
    
    Requirements:
    1. Page exists as child of Project Roadmap
    2. heading1 with report title
    3. Executive Dashboard with conditional color callout (yellow for 50-75%)
    4. Goals Analysis, Quality Metrics, Team Velocity, Q2 Readiness sections
    5. Recommended Actions with 3 numbered items
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    try:
        try:
            # Find the report page - try multiple search terms
            report_pages = _get_pages(backend, "Quarterly Project Health Report")
            if not report_pages:
                report_pages = _get_pages(backend, "Health Report")
            if not report_pages:
                report_pages = _get_pages(backend, "Quarterly")
            if not report_pages:
                report_pages = _get_pages(backend, "Q1 2024")
            if not report_pages:
                errors.append("[X] Quarterly Project Health Report page not found")
            else:
                checks_passed.append("[C] Quarterly Project Health Report page found")
        
            page = report_pages[0]
            page_id = page.get("_id")
            blocks = _get_blocks(backend, page_id)
        
            if not blocks:
                errors.append("[X] Quarterly Project Health Report page has no blocks")
            else:
                checks_passed.append("[C] Quarterly Project Health Report page has blocks")
        
            # Check page is child of Project Roadmap
            parent_id = page.get("parentId")
            if parent_id:
                roadmap_pages = _get_pages(backend, "Project Roadmap")
                if roadmap_pages and roadmap_pages[0].get("_id") != parent_id:
                    pass  # Allow flexibility on parent
        
            missing = []
        
            # Check for heading1 with report title
            title_found = False
            for block in blocks:
                if block.get("type") == "heading1" and "Health Report" in block.get("content", ""):
                    title_found = True
                    break
        
            if not title_found:
                missing.append("heading1 '🏥 Q1 2024 Project Health Report'")
        
            # Check for Executive Dashboard heading
            dashboard_found = False
            for block in blocks:
                if block.get("type") == "heading2" and "Executive Dashboard" in block.get("content", ""):
                    dashboard_found = True
                    break
        
            if not dashboard_found:
                missing.append("heading2 '📊 Executive Dashboard'")
        
            # Check for status callout (should be yellow for 50-75% range)
            status_callout_found = False
            for block in blocks:
                if block.get("type") == "callout":
                    content = block.get("content", "")
                    props = block.get("properties", {})
                    bg_color = props.get("backgroundColor", "")
                    icon = props.get("icon", "")
                
                    if "Health Status" in content or "Status" in content:
                        # Check for valid status indicators
                        if ("Warning" in content or "warning" in content.lower() or 
                            "Critical" in content or "Healthy" in content):
                            status_callout_found = True
                            # Prefer yellow for 66.7% completion
                            if bg_color == "yellow_background":
                                pass  # Correct for warning status
                            break
        
            if not status_callout_found:
                missing.append("status callout with Health Status text")
        
            # Check for Goals Analysis heading
            goals_found = False
            for block in blocks:
                if block.get("type") == "heading2" and "Goals" in block.get("content", ""):
                    goals_found = True
                    break
        
            if not goals_found:
                missing.append("heading2 '🎯 Goals Analysis'")
        
            # Check for Quality Metrics heading
            quality_found = False
            for block in blocks:
                if block.get("type") == "heading2" and ("Quality" in block.get("content", "") or 
                                                         "Bug" in block.get("content", "")):
                    quality_found = True
                    break
        
            if not quality_found:
                missing.append("heading2 '🐛 Quality Metrics'")
        
            # Check for Team Velocity heading
            velocity_found = False
            for block in blocks:
                if block.get("type") == "heading2" and "Velocity" in block.get("content", ""):
                    velocity_found = True
                    break
        
            if not velocity_found:
                missing.append("heading2 '👥 Team Velocity'")
        
            # Check for Q2 Readiness heading
            q2_found = False
            for block in blocks:
                if block.get("type") == "heading2" and ("Q2" in block.get("content", "") or 
                                                         "Readiness" in block.get("content", "")):
                    q2_found = True
                    break
        
            if not q2_found:
                missing.append("heading2 '🔮 Q2 Readiness'")
        
            # Check for Recommended Actions heading
            actions_found = False
            for block in blocks:
                if block.get("type") == "heading2" and ("Recommended" in block.get("content", "") or 
                                                         "Actions" in block.get("content", "")):
                    actions_found = True
                    break
        
            if not actions_found:
                missing.append("heading2 '💊 Recommended Actions'")
        
            # Check for numbered list items (recommendations)
            numbered_items = [b for b in blocks if b.get("type") == "numberedList"]
            if len(numbered_items) < 3:
                missing.append(f"3 numbered recommendations (found {len(numbered_items)})")
        
            if missing:
                errors.append(f"[X] Quarterly Health Report is missing: {', '.join(missing)}")
            else:
                checks_passed.append(f"[C] Quarterly Health Report is has")
        
            return TaskScore(
                score=1.0 if len(errors) == 0 else 0.0,
                metadata=ScoreMetadata(
                    success_accumulator=list(dict.fromkeys(checks_passed)),
                    error_accumulator=list(dict.fromkeys(errors)),
                )
            )
    
        except Exception as e:
            errors.append(f"[X] Error validating quarterly health report: {str(e)}")
            return TaskScore(
                score=0.0,
                metadata=ScoreMetadata(
                    success_accumulator=list(dict.fromkeys(checks_passed)),
                    error_accumulator=list(dict.fromkeys(errors)),
                )
            )

    # -----------------------------------------------------------------------------
    # create-onboarding-progress-tracker-v2
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_create_onboarding_progress_tracker(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validates the onboarding progress tracker page.
    
    Requirements:
    1. Page exists as child of Onboarding Guide
    2. heading1 with tracker title
    3. Employee name and start date headings
    4. Sections with todos preserving checked status
    5. Progress Summary with callout showing percentage
    6. Achievements section with completed tasks
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    try:
        try:
            # Find the tracker page
            tracker_pages = _get_pages(backend, "Onboarding Progress Tracker")
            if not tracker_pages:
                tracker_pages = _get_pages(backend, "Progress Tracker")
            if not tracker_pages:
                errors.append("[X] Onboarding Progress Tracker page not found")
            else:
                checks_passed.append("[C] Onboarding Progress Tracker page found")
        
            page = tracker_pages[0]
            page_id = page.get("_id")
            blocks = _get_blocks(backend, page_id)
        
            if not blocks:
                errors.append("[X] Onboarding Progress Tracker page has no blocks")
            else:
                checks_passed.append("[C] Onboarding Progress Tracker page has blocks")
        
            missing = []
        
            # Check for heading1 with tracker title
            title_found = False
            for block in blocks:
                if block.get("type") == "heading1" and "Progress Tracker" in block.get("content", ""):
                    title_found = True
                    break
        
            if not title_found:
                missing.append("heading1 '📊 Onboarding Progress Tracker'")
        
            # Check for Employee heading
            employee_found = False
            for block in blocks:
                if block.get("type") == "heading2" and ("Employee" in block.get("content", "") or 
                                                         "Name" in block.get("content", "")):
                    employee_found = True
                    break
        
            if not employee_found:
                missing.append("heading2 with Employee name")
        
            # Check for Start Date heading
            date_found = False
            for block in blocks:
                if block.get("type") == "heading3" and "Start Date" in block.get("content", ""):
                    date_found = True
                    break
        
            if not date_found:
                missing.append("heading3 with Start Date")
        
            # Check for Progress Summary heading
            summary_found = False
            for block in blocks:
                if block.get("type") == "heading2" and ("Progress Summary" in block.get("content", "") or 
                                                         "Summary" in block.get("content", "")):
                    summary_found = True
                    break
        
            if not summary_found:
                missing.append("heading2 '📈 Progress Summary'")
        
            # Check for callout with progress stats
            progress_callout_found = False
            for block in blocks:
                if block.get("type") == "callout":
                    content = block.get("content", "")
                    props = block.get("properties", {})
                    if "Progress" in content and "%" in content:
                        if props.get("backgroundColor") == "blue_background":
                            progress_callout_found = True
                            break
        
            if not progress_callout_found:
                missing.append("blue callout with progress percentage")
        
            # Check for Achievements heading
            achievements_found = False
            for block in blocks:
                if block.get("type") == "heading3" and "Achievements" in block.get("content", ""):
                    achievements_found = True
                    break
        
            if not achievements_found:
                missing.append("heading3 '🏆 Achievements'")
        
            # Check for divider
            divider_found = any(b.get("type") == "divider" for b in blocks)
            if not divider_found:
                missing.append("divider before Progress Summary")
        
            # Check for bulleted list (achievements)
            bullet_items = [b for b in blocks if b.get("type") == "bulletedList"]
            if len(bullet_items) < 1:
                missing.append("bulleted list for achievements")
        
            if missing:
                errors.append(f"[X] Onboarding Progress Tracker is missing: {', '.join(missing)}")
            else:
                checks_passed.append(f"[C] Onboarding Progress Tracker is has")
        
            return TaskScore(
                score=1.0 if len(errors) == 0 else 0.0,
                metadata=ScoreMetadata(
                    success_accumulator=list(dict.fromkeys(checks_passed)),
                    error_accumulator=list(dict.fromkeys(errors)),
                )
            )
    
        except Exception as e:
            errors.append(f"[X] Error validating onboarding progress tracker: {str(e)}")
            return TaskScore(
                score=0.0,
                metadata=ScoreMetadata(
                    success_accumulator=list(dict.fromkeys(checks_passed)),
                    error_accumulator=list(dict.fromkeys(errors)),
                )
            )

    # -----------------------------------------------------------------------------
    # create-bug-triage-dashboard-v2
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_create_bug_triage_dashboard(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validates the bug triage dashboard page.
    
    Requirements:
    1. Page exists as child of Bug Tracker
    2. heading1 with dashboard title and 🐛 emoji
    3. Critical Issues section with unchecked todos as numbered list
    4. Resolved Issues section with checked todos
    5. Divider
    6. Bug Statistics section with 3 callouts (red, yellow, green)
    7. Accurate counts and resolution rate
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    try:
        try:
            # Find the dashboard page
            dashboard_pages = _get_pages(backend, "Bug Triage Dashboard")
            if not dashboard_pages:
                dashboard_pages = _get_pages(backend, "Triage Dashboard")
            if not dashboard_pages:
                errors.append("[X] Bug Triage Dashboard page not found")
            else:
                checks_passed.append("[C] Bug Triage Dashboard page found")
        
            page = dashboard_pages[0]
            page_id = page.get("_id")
            blocks = _get_blocks(backend, page_id)
        
            if not blocks:
                errors.append("[X] Bug Triage Dashboard page has no blocks")
            else:
                checks_passed.append("[C] Bug Triage Dashboard page has blocks")
        
            # Check parent is Bug Tracker
            parent_id = page.get("parentId")
            if parent_id:
                bug_tracker_pages = _get_pages(backend, "Bug Tracker")
                if bug_tracker_pages and bug_tracker_pages[0].get("_id") != parent_id:
                    pass  # Allow some flexibility
        
            missing = []
        
            # Check for heading1 with dashboard title
            title_found = False
            for block in blocks:
                if block.get("type") == "heading1":
                    content = block.get("content", "")
                    if "Bug Triage" in content or "Triage Dashboard" in content:
                        title_found = True
                        break
        
            if not title_found:
                missing.append("heading1 '🐛 Bug Triage Dashboard'")
        
            # Check for Critical Issues heading
            critical_found = False
            for block in blocks:
                if block.get("type") == "heading2" and ("Critical" in block.get("content", "") or 
                                                         "Issues" in block.get("content", "")):
                    critical_found = True
                    break
        
            if not critical_found:
                missing.append("heading2 '🚨 Critical Issues'")
        
            # Check for Resolved Issues heading
            resolved_found = False
            for block in blocks:
                if block.get("type") == "heading2" and "Resolved" in block.get("content", ""):
                    resolved_found = True
                    break
        
            if not resolved_found:
                missing.append("heading2 '✅ Resolved Issues'")
        
            # Check for Bug Statistics heading
            stats_found = False
            for block in blocks:
                if block.get("type") == "heading2" and ("Statistics" in block.get("content", "") or 
                                                         "Stats" in block.get("content", "")):
                    stats_found = True
                    break
        
            if not stats_found:
                missing.append("heading2 '📊 Bug Statistics'")
        
            # Check for divider
            divider_found = any(b.get("type") == "divider" for b in blocks)
            if not divider_found:
                missing.append("divider")
        
            # Check for 3 callouts with different colors
            callouts = [b for b in blocks if b.get("type") == "callout"]
            if len(callouts) < 3:
                missing.append(f"3 callout blocks (found {len(callouts)})")
            else:
                # Check for red, yellow, green backgrounds
                bg_colors = [c.get("properties", {}).get("backgroundColor", "") for c in callouts]
                if "red_background" not in bg_colors:
                    missing.append("red_background callout")
                if "yellow_background" not in bg_colors:
                    missing.append("yellow_background callout")
                if "green_background" not in bg_colors:
                    missing.append("green_background callout")
        
            # Check for numbered list (Critical Issues)
            numbered_items = [b for b in blocks if b.get("type") == "numberedList"]
            if len(numbered_items) < 1:
                missing.append("numbered list for Critical Issues")
        
            if missing:
                errors.append(f"[X] Bug Triage Dashboard is missing: {', '.join(missing)}")
            else:
                checks_passed.append(f"[C] Bug Triage Dashboard is has")
        
            return TaskScore(
                score=1.0 if len(errors) == 0 else 0.0,
                metadata=ScoreMetadata(
                    success_accumulator=list(dict.fromkeys(checks_passed)),
                    error_accumulator=list(dict.fromkeys(errors)),
                )
            )
    
        except Exception as e:
            errors.append(f"[X] Error validating bug triage dashboard: {str(e)}")
            return TaskScore(
                score=0.0,
                metadata=ScoreMetadata(
                    success_accumulator=list(dict.fromkeys(checks_passed)),
                    error_accumulator=list(dict.fromkeys(errors)),
                )
            )

    # -----------------------------------------------------------------------------
    # add-team-directory-alumni-v2
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_add_team_directory_alumni(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validates the Alumni section added to Team Directory page.
    
    Requirements:
    1. Team Directory page has new content at the end
    2. Divider before Alumni section
    3. heading_2 '🎓 Alumni' with intro paragraph
    4. Sarah Chen entry with heading_3, 3 bulletedList, quote
    5. Michael Torres heading_3
    6. Blue callout with 💙 icon at the end
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    try:
        try:
            # Find the Team Directory page
            directory_pages = _get_pages(backend, "Team Directory")
            if not directory_pages:
                errors.append("[X] Team Directory page not found")
            else:
                checks_passed.append("[C] Team Directory page found")
        
            page = directory_pages[0]
            page_id = page.get("_id")
            blocks = _get_blocks(backend, page_id)
        
            if not blocks:
                errors.append("[X] Team Directory page has no blocks")
            else:
                checks_passed.append("[C] Team Directory page has blocks")
        
            missing = []
        
            # Check for divider
            divider_found = any(b.get("type") == "divider" for b in blocks)
            if not divider_found:
                missing.append("divider before Alumni section")
        
            # Check for Alumni heading
            alumni_found = False
            for block in blocks:
                if block.get("type") == "heading2" and "Alumni" in block.get("content", ""):
                    alumni_found = True
                    break
        
            if not alumni_found:
                missing.append("heading2 '🎓 Alumni'")
        
            # Check for intro paragraph
            intro_found = False
            for block in blocks:
                if block.get("type") == "paragraph" and "Former team members" in block.get("content", ""):
                    intro_found = True
                    break
        
            if not intro_found:
                missing.append("intro paragraph about former team members")
        
            # Check for Sarah Chen heading
            sarah_found = False
            for block in blocks:
                if block.get("type") == "heading3" and "Sarah Chen" in block.get("content", ""):
                    sarah_found = True
                    break
        
            if not sarah_found:
                missing.append("heading3 '👤 Sarah Chen'")
        
            # Check for Michael Torres heading
            michael_found = False
            for block in blocks:
                if block.get("type") == "heading3" and "Michael Torres" in block.get("content", ""):
                    michael_found = True
                    break
        
            if not michael_found:
                missing.append("heading3 '👤 Michael Torres'")
        
            # Check for bulletedList items
            bullet_items = [b for b in blocks if b.get("type") == "bulletedList"]
            role_found = any("Role" in b.get("content", "") for b in bullet_items)
            tenure_found = any("Tenure" in b.get("content", "") for b in bullet_items)
            contributions_found = any("Contributions" in b.get("content", "") for b in bullet_items)
        
            if not role_found:
                missing.append("bulletedList with Role")
            if not tenure_found:
                missing.append("bulletedList with Tenure")
            if not contributions_found:
                missing.append("bulletedList with Key Contributions")
        
            # Check for quote block
            quote_found = False
            for block in blocks:
                if block.get("type") == "quote":
                    content = block.get("content", "")
                    if "growth opportunity" in content or "innovation" in content:
                        quote_found = True
                        break
        
            if not quote_found:
                missing.append("quote block about growth opportunity")
        
            # Check for blue callout with networking text
            callout_found = False
            for block in blocks:
                if block.get("type") == "callout":
                    props = block.get("properties", {})
                    content = block.get("content", "")
                    if (props.get("backgroundColor") == "blue_background" and 
                        ("alumni" in content.lower() or "mentorship" in content.lower())):
                        callout_found = True
                        break
        
            if not callout_found:
                missing.append("blue callout with alumni network text")
        
            if missing:
                errors.append(f"[X] Team Directory Alumni section is missing: {', '.join(missing)}")
            else:
                checks_passed.append(f"[C] Team Directory Alumni section is has")
        
            return TaskScore(
                score=1.0 if len(errors) == 0 else 0.0,
                metadata=ScoreMetadata(
                    success_accumulator=list(dict.fromkeys(checks_passed)),
                    error_accumulator=list(dict.fromkeys(errors)),
                )
            )
    
        except Exception as e:
            errors.append(f"[X] Error validating team directory alumni: {str(e)}")
            return TaskScore(
                score=0.0,
                metadata=ScoreMetadata(
                    success_accumulator=list(dict.fromkeys(checks_passed)),
                    error_accumulator=list(dict.fromkeys(errors)),
                )
            )

    # -----------------------------------------------------------------------------
    # add-prd-document-navigation-v2
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_add_prd_document_navigation(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validates Document Navigation and Revision History added to PRD page.
    
    Requirements:
    1. Navigation section appears immediately after heading_1
    2. Blue callout with accurate heading counts
    3. Numbered list contains all heading_2 titles as table of contents
    4. Revision History appears after third original heading_2
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    try:
        try:
            # Find the PRD page
            prd_pages = _get_pages(backend, "Comprehensive Product Requirements Document")
            if not prd_pages:
                errors.append("[X] Comprehensive Product Requirements Document page not found")
            else:
                checks_passed.append("[C] Comprehensive Product Requirements Document page found")
        
            page = prd_pages[0]
            page_id = page.get("_id")
            blocks = _get_blocks(backend, page_id)
        
            if not blocks:
                errors.append("[X] PRD page has no blocks")
            else:
                checks_passed.append("[C] PRD page has blocks")
        
            missing = []
        
            # Check for Document Navigation heading after heading_1
            nav_heading_found = False
            nav_heading_index = -1
            for i, block in enumerate(blocks):
                if block.get("type") == "heading2" and "Document Navigation" in block.get("content", ""):
                    nav_heading_found = True
                    nav_heading_index = i
                    break
        
            if not nav_heading_found:
                missing.append("heading_2 '🧭 Document Navigation'")
        
            # Verify navigation appears after heading_1 (index 0 should be heading_1)
            if nav_heading_found and nav_heading_index > 0:
                first_block = blocks[0]
                if first_block.get("type") != "heading1":
                    missing.append("navigation section not immediately after heading_1")
        
            # Check for blue callout with heading counts
            callout_found = False
            for block in blocks:
                if block.get("type") == "callout":
                    props = block.get("properties", {})
                    content = block.get("content", "")
                    if (props.get("backgroundColor") == "blue_background" and 
                        "sections" in content.lower() and "subsections" in content.lower()):
                        callout_found = True
                        break
        
            if not callout_found:
                missing.append("blue callout with heading counts")
        
            # Check for numbered list items (table of contents)
            numbered_items = [b for b in blocks if b.get("type") == "numberedList"]
            if len(numbered_items) < 2:
                missing.append("numbered list table of contents")
        
            # Check for Revision History section
            revision_found = False
            for block in blocks:
                if block.get("type") == "heading2" and "Revision History" in block.get("content", ""):
                    revision_found = True
                    break
        
            if not revision_found:
                missing.append("heading_2 '🔄 Revision History'")
        
            # Check for version entries
            version_entries = [b for b in blocks if b.get("type") == "bulletedList"]
            version_1_found = any("Version 1.0" in b.get("content", "") for b in version_entries)
            version_11_found = any("Version 1.1" in b.get("content", "") for b in version_entries)
            version_2_found = any("Version 2.0" in b.get("content", "") for b in version_entries)
        
            if not version_1_found:
                missing.append("Version 1.0 bullet point")
            if not version_11_found:
                missing.append("Version 1.1 bullet point")
            if not version_2_found:
                missing.append("Version 2.0 bullet point")
        
            if missing:
                errors.append(f"[X] PRD Document Navigation is missing: {', '.join(missing)}")
            else:
                checks_passed.append(f"[C] PRD Document Navigation is has")
        
            return TaskScore(
                score=1.0 if len(errors) == 0 else 0.0,
                metadata=ScoreMetadata(
                    success_accumulator=list(dict.fromkeys(checks_passed)),
                    error_accumulator=list(dict.fromkeys(errors)),
                )
            )
    
        except Exception as e:
            errors.append(f"[X] Error validating PRD document navigation: {str(e)}")
            return TaskScore(
                score=0.0,
                metadata=ScoreMetadata(
                    success_accumulator=list(dict.fromkeys(checks_passed)),
                    error_accumulator=list(dict.fromkeys(errors)),
                )
            )

    # -----------------------------------------------------------------------------
    # add-handbook-quick-reference-v2
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_add_handbook_quick_reference(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validates Quick Reference section added to Company Handbook.
    
    Requirements:
    1. heading_1 '⚡ Quick Reference Guide' is the first block
    2. heading_2 '📋 Key Policies Summary' exists
    3. Policy summaries with gray callouts for sections with numbered lists
    4. heading_2 '🎯 Action Items' exists
    5. Todo blocks created from original bulleted list items
    6. Divider and italic paragraph with date at end
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    try:
        try:
            # Find the Company Handbook page
            handbook_pages = _get_pages(backend, "Company Handbook")
            if not handbook_pages:
                errors.append("[X] Company Handbook page not found")
            else:
                checks_passed.append("[C] Company Handbook page found")
        
            page = handbook_pages[0]
            page_id = page.get("_id")
            blocks = _get_blocks(backend, page_id)
        
            if not blocks:
                errors.append("[X] Company Handbook page has no blocks")
            else:
                checks_passed.append("[C] Company Handbook page has blocks")
        
            missing = []
        
            # Check first block is Quick Reference heading
            first_block = blocks[0]
            if not (first_block.get("type") == "heading1" and 
                    "Quick Reference" in first_block.get("content", "")):
                missing.append("heading_1 '⚡ Quick Reference Guide' as first block")
        
            # Check for Key Policies Summary heading
            policies_found = False
            for block in blocks:
                if block.get("type") == "heading2" and "Key Policies Summary" in block.get("content", ""):
                    policies_found = True
                    break
        
            if not policies_found:
                missing.append("heading_2 '📋 Key Policies Summary'")
        
            # Check for gray callouts with policy counts
            gray_callouts = [b for b in blocks if 
                            b.get("type") == "callout" and 
                            b.get("properties", {}).get("backgroundColor") == "gray_background" and
                            "policy items" in b.get("content", "").lower()]
        
            if len(gray_callouts) < 1:
                missing.append("gray callout with policy item count")
        
            # Check for Action Items heading
            action_items_found = False
            for block in blocks:
                if block.get("type") == "heading2" and "Action Items" in block.get("content", ""):
                    action_items_found = True
                    break
        
            if not action_items_found:
                missing.append("heading_2 '🎯 Action Items'")
        
            # Check for todo blocks
            todo_blocks = [b for b in blocks if b.get("type") == "todo"]
            if len(todo_blocks) < 1:
                missing.append("todo blocks under Action Items")
        
            # Check for divider
            divider_found = any(b.get("type") == "divider" for b in blocks)
            if not divider_found:
                missing.append("divider")
        
            # Check for italic paragraph with date
            italic_para_found = False
            for block in blocks:
                if block.get("type") == "paragraph":
                    props = block.get("properties", {})
                    content = block.get("content", "")
                    if props.get("italic") and "Generated on" in content:
                        italic_para_found = True
                        break
        
            if not italic_para_found:
                missing.append("italic paragraph with 'Generated on' date")
        
            if missing:
                errors.append(f"[X] Handbook Quick Reference is missing: {', '.join(missing)}")
            else:
                checks_passed.append(f"[C] Handbook Quick Reference is has")
        
            return TaskScore(
                score=1.0 if len(errors) == 0 else 0.0,
                metadata=ScoreMetadata(
                    success_accumulator=list(dict.fromkeys(checks_passed)),
                    error_accumulator=list(dict.fromkeys(errors)),
                )
            )
    
        except Exception as e:
            errors.append(f"[X] Error validating handbook quick reference: {str(e)}")
            return TaskScore(
                score=0.0,
                metadata=ScoreMetadata(
                    success_accumulator=list(dict.fromkeys(checks_passed)),
                    error_accumulator=list(dict.fromkeys(errors)),
                )
            )

    # -----------------------------------------------------------------------------
    # add-wiki-docker-setup-v2
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_add_wiki_docker_setup(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validates Docker Setup and Redis cache added to Engineering Wiki.
    
    Requirements:
    1. heading_3 '🐳 Docker Setup (Optional)' exists
    2. Code block with language 'bash' and Docker commands
    3. Blue callout with no icon about Docker setup
    4. New bulletedList item for Redis cache
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    try:
        try:
            # Find the Engineering Wiki page
            wiki_pages = _get_pages(backend, "Engineering Wiki")
            if not wiki_pages:
                errors.append("[X] Engineering Wiki page not found")
            else:
                checks_passed.append("[C] Engineering Wiki page found")
        
            page = wiki_pages[0]
            page_id = page.get("_id")
            blocks = _get_blocks(backend, page_id)
        
            if not blocks:
                errors.append("[X] Engineering Wiki page has no blocks")
            else:
                checks_passed.append("[C] Engineering Wiki page has blocks")
        
            missing = []
        
            # Check for Docker Setup heading
            docker_heading_found = False
            for block in blocks:
                if block.get("type") == "heading3" and "Docker Setup" in block.get("content", ""):
                    docker_heading_found = True
                    break
        
            if not docker_heading_found:
                missing.append("heading_3 '🐳 Docker Setup (Optional)'")
        
            # Check for bash code block with Docker commands
            code_block_found = False
            for block in blocks:
                if block.get("type") == "code":
                    props = block.get("properties", {})
                    content = block.get("content", "")
                    if (props.get("language") == "bash" and 
                        "docker" in content.lower()):
                        code_block_found = True
                        break
        
            if not code_block_found:
                missing.append("code block with language 'bash' and Docker commands")
        
            # Check for blue callout about Docker
            docker_callout_found = False
            for block in blocks:
                if block.get("type") == "callout":
                    props = block.get("properties", {})
                    content = block.get("content", "")
                    if (props.get("backgroundColor") == "blue_background" and
                        "docker" in content.lower()):
                        docker_callout_found = True
                        break
        
            if not docker_callout_found:
                missing.append("blue callout about Docker setup")
        
            # Check for Redis bulletedList item
            redis_found = False
            for block in blocks:
                if block.get("type") == "bulletedList":
                    content = block.get("content", "")
                    if "redis" in content.lower() and "cache" in content.lower():
                        redis_found = True
                        break
        
            if not redis_found:
                missing.append("bulletedList item for Redis cache")
        
            if missing:
                errors.append(f"[X] Wiki Docker Setup is missing: {', '.join(missing)}")
            else:
                checks_passed.append("[C] Wiki Docker Setup has all required elements")
        
            return TaskScore(
                score=1.0 if len(errors) == 0 else 0.0,
                metadata=ScoreMetadata(
                    success_accumulator=list(dict.fromkeys(checks_passed)),
                    error_accumulator=list(dict.fromkeys(errors)),
                )
            )
    
        except Exception as e:
            errors.append(f"[X] Error validating wiki docker setup: {str(e)}")
            return TaskScore(
                score=0.0,
                metadata=ScoreMetadata(
                    success_accumulator=list(dict.fromkeys(checks_passed)),
                    error_accumulator=list(dict.fromkeys(errors)),
                )
            )

    # -----------------------------------------------------------------------------
    # add-python-examples-section-v2
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_add_python_examples_section(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validates Python Examples section added to Code Examples Repository.
    
    Requirements:
    1. heading_2 '🐍 Python Examples' exists
    2. Paragraph about Python patterns
    3. heading_3 '📦 Data Processing' with python code block
    4. Blue callout about validation
    5. heading_3 '🔐 Authentication Decorator' with python code block
    6. Divider at the end
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    try:
        try:
            # Find the Code Examples Repository page
            repo_pages = _get_pages(backend, "Code Examples Repository")
            if not repo_pages:
                errors.append("[X] Code Examples Repository page not found")
            else:
                checks_passed.append("[C] Code Examples Repository page found")
        
            page = repo_pages[0]
            page_id = page.get("_id")
            blocks = _get_blocks(backend, page_id)
        
            if not blocks:
                errors.append("[X] Code Examples Repository page has no blocks")
            else:
                checks_passed.append("[C] Code Examples Repository page has blocks")
        
            missing = []
        
            # Check for Python Examples heading
            python_heading_found = False
            for block in blocks:
                if block.get("type") == "heading2" and "Python Examples" in block.get("content", ""):
                    python_heading_found = True
                    break
        
            if not python_heading_found:
                missing.append("heading_2 '🐍 Python Examples'")
        
            # Check for intro paragraph
            intro_found = False
            for block in blocks:
                if block.get("type") == "paragraph":
                    content = block.get("content", "")
                    if "python" in content.lower() and "pattern" in content.lower():
                        intro_found = True
                        break
        
            if not intro_found:
                missing.append("paragraph about Python patterns")
        
            # Check for Data Processing heading
            data_heading_found = False
            for block in blocks:
                if block.get("type") == "heading3" and "Data Processing" in block.get("content", ""):
                    data_heading_found = True
                    break
        
            if not data_heading_found:
                missing.append("heading_3 '📦 Data Processing'")
        
            # Check for python code blocks
            python_code_blocks = [b for b in blocks if 
                                 b.get("type") == "code" and 
                                 b.get("properties", {}).get("language") == "python"]
        
            if len(python_code_blocks) < 2:
                missing.append("two python code blocks")
        
            # Check for blue callout
            callout_found = False
            for block in blocks:
                if block.get("type") == "callout":
                    props = block.get("properties", {})
                    content = block.get("content", "")
                    if (props.get("backgroundColor") == "blue_background" and
                        "validate" in content.lower()):
                        callout_found = True
                        break
        
            if not callout_found:
                missing.append("blue callout about validation")
        
            # Check for Authentication heading
            auth_heading_found = False
            for block in blocks:
                if block.get("type") == "heading3" and "Authentication" in block.get("content", ""):
                    auth_heading_found = True
                    break
        
            if not auth_heading_found:
                missing.append("heading_3 '🔐 Authentication Decorator'")
        
            # Check for divider
            divider_found = any(b.get("type") == "divider" for b in blocks)
            if not divider_found:
                missing.append("divider at section end")
        
            if missing:
                errors.append(f"[X] Python Examples section is missing: {', '.join(missing)}")
            else:
                checks_passed.append(f"[C] Python Examples section is has")
        
            return TaskScore(
                score=1.0 if len(errors) == 0 else 0.0,
                metadata=ScoreMetadata(
                    success_accumulator=list(dict.fromkeys(checks_passed)),
                    error_accumulator=list(dict.fromkeys(errors)),
                )
            )
    
        except Exception as e:
            errors.append(f"[X] Error validating python examples section: {str(e)}")
            return TaskScore(
                score=0.0,
                metadata=ScoreMetadata(
                    success_accumulator=list(dict.fromkeys(checks_passed)),
                    error_accumulator=list(dict.fromkeys(errors)),
                )
            )

    # -----------------------------------------------------------------------------
    # add-learning-platforms-resources-v2
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_add_learning_platforms_resources(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validates learning platforms resources added to External Resources page.
    
    Requirements:
    1. Image block exists before MDN Web Docs bookmark with correct URL/caption
    2. heading_3 '📚 Learning Platforms' exists between divider and 'Tools' heading
    3. Three bookmarks under Learning Platforms: FreeCodeCamp, Coursera, Udemy
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    try:
        try:
            # Find the External Resources & Links page
            resources_pages = _get_pages(backend, "External Resources")
            if not resources_pages:
                errors.append("[X] External Resources & Links page not found")
            else:
                checks_passed.append("[C] External Resources & Links page found")
        
            page = resources_pages[0]
            page_id = page.get("_id")
            blocks = _get_blocks(backend, page_id)
        
            if not blocks:
                errors.append("[X] External Resources page has no blocks")
            else:
                checks_passed.append("[C] External Resources page has blocks")
        
            missing = []
        
            # Find MDN Web Docs bookmark in Documentation section
            mdn_index = -1
            for i, block in enumerate(blocks):
                if block.get("type") == "bookmark" and "MDN" in block.get("content", ""):
                    mdn_index = i
                    break
        
            if mdn_index == -1:
                missing.append("MDN Web Docs bookmark")
            else:
                # Check for image block before MDN bookmark
                image_found = False
                for i in range(mdn_index):
                    block = blocks[i]
                    if block.get("type") == "image":
                        content = block.get("content", "")
                        if "developer.mozilla.org" in content or "opengraph-logo" in content:
                            image_found = True
                            break
            
                if not image_found:
                    missing.append("image block before MDN Web Docs bookmark")
        
            # Find the divider between Documentation and Tools
            divider_index = -1
            tools_index = -1
            for i, block in enumerate(blocks):
                if block.get("type") == "divider":
                    divider_index = i
                if block.get("type") == "heading2" and block.get("content") == "Tools":
                    tools_index = i
                    break
        
            if divider_index == -1 or tools_index == -1:
                missing.append("divider or Tools heading")
            else:
                # Check for Learning Platforms heading_3 between divider and Tools
                learning_heading_found = False
                for i in range(divider_index + 1, tools_index):
                    block = blocks[i]
                    if block.get("type") == "heading3" and "Learning Platforms" in block.get("content", ""):
                        learning_heading_found = True
                    
                        # Check for 3 bookmarks after Learning Platforms heading
                        bookmarks_to_check = [
                            ("FreeCodeCamp", "https://www.freecodecamp.org"),
                            ("Coursera", "https://www.coursera.org"),
                            ("Udemy", "https://www.udemy.com")
                        ]
                    
                        bookmark_count = 0
                        for j in range(i + 1, min(i + 4, len(blocks))):
                            b = blocks[j]
                            if b.get("type") == "bookmark":
                                bookmark_count += 1
                    
                        if bookmark_count < 3:
                            missing.append(f"3 bookmarks under Learning Platforms (found {bookmark_count})")
                        break
            
                if not learning_heading_found:
                    missing.append("heading_3 '📚 Learning Platforms' between divider and Tools")
        
            # Check for specific bookmarks
            freecodecamp_found = False
            coursera_found = False
            udemy_found = False
        
            for block in blocks:
                if block.get("type") == "bookmark":
                    props = block.get("properties", {})
                    url = props.get("url", "")
                    if "freecodecamp" in url.lower():
                        freecodecamp_found = True
                    if "coursera" in url.lower():
                        coursera_found = True
                    if "udemy" in url.lower():
                        udemy_found = True
        
            if not freecodecamp_found:
                missing.append("FreeCodeCamp bookmark")
            if not coursera_found:
                missing.append("Coursera bookmark")
            if not udemy_found:
                missing.append("Udemy bookmark")
        
            if missing:
                errors.append(f"[X] Learning platforms resources missing: {', '.join(missing)}")
            else:
                checks_passed.append(f"[C] Learning platforms resources has")
        
            return TaskScore(
                score=1.0 if len(errors) == 0 else 0.0,
                metadata=ScoreMetadata(
                    success_accumulator=list(dict.fromkeys(checks_passed)),
                    error_accumulator=list(dict.fromkeys(errors)),
                )
            )
    
        except Exception as e:
            errors.append(f"[X] Error validating learning platforms resources: {str(e)}")
            return TaskScore(
                score=0.0,
                metadata=ScoreMetadata(
                    success_accumulator=list(dict.fromkeys(checks_passed)),
                    error_accumulator=list(dict.fromkeys(errors)),
                )
            )

    # -----------------------------------------------------------------------------
    # add-mid-sprint-review-section-v2
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_add_mid_sprint_review_section(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validates Mid-Sprint Review section added to Sprint Planning page.
    
    Requirements:
    1. heading_2 '🎯 Mid-Sprint Review' exists between Sprint Goals and Action Items
    2. Yellow callout with 📊 icon and specific text
    3. Three unchecked to-do blocks with specific texts
    4. Divider before Action Items section
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    try:
        try:
            # Find the Sprint Planning page
            sprint_pages = _get_pages(backend, "Sprint Planning")
            if not sprint_pages:
                errors.append("[X] Sprint Planning page not found")
            else:
                checks_passed.append("[C] Sprint Planning page found")
        
            page = sprint_pages[0]
            page_id = page.get("_id")
            blocks = _get_blocks(backend, page_id)
        
            if not blocks:
                errors.append("[X] Sprint Planning page has no blocks")
            else:
                checks_passed.append("[C] Sprint Planning page has blocks")
        
            missing = []
        
            # Find Sprint Goals heading
            sprint_goals_idx = -1
            for i, block in enumerate(blocks):
                if block.get("type") == "heading2" and "Sprint Goals" in block.get("content", ""):
                    sprint_goals_idx = i
                    break
        
            # Find Action Items heading
            action_items_idx = -1
            for i, block in enumerate(blocks):
                if block.get("type") == "heading2" and "Action Items" in block.get("content", ""):
                    action_items_idx = i
                    break
        
            if sprint_goals_idx == -1:
                missing.append("Sprint Goals heading")
            if action_items_idx == -1:
                missing.append("Action Items heading")
        
            # Check for Mid-Sprint Review heading between Sprint Goals and Action Items
            mid_sprint_found = False
            mid_sprint_idx = -1
            for i, block in enumerate(blocks):
                if block.get("type") == "heading2" and "Mid-Sprint Review" in block.get("content", ""):
                    mid_sprint_found = True
                    mid_sprint_idx = i
                    break
        
            if not mid_sprint_found:
                missing.append("heading_2 '🎯 Mid-Sprint Review'")
        
            # Check for yellow callout with stats icon
            callout_found = False
            for block in blocks:
                if block.get("type") == "callout":
                    props = block.get("properties", {})
                    content = block.get("content", "")
                    if (props.get("backgroundColor") == "yellow_background" and
                        "Progress update" in content and "January 22" in content):
                        callout_found = True
                        break
        
            if not callout_found:
                missing.append("yellow callout with progress update text")
        
            # Check for the three todo blocks
            todo_texts = [
                "Review authentication flow progress with Alice",
                "Check drag-and-drop implementation status",
                "Assess sharing UI mockups"
            ]
        
            for text in todo_texts:
                found = False
                for block in blocks:
                    if block.get("type") == "todo" and text in block.get("content", ""):
                        props = block.get("properties", {})
                        if not props.get("checked", False):
                            found = True
                            break
                if not found:
                    missing.append(f"unchecked todo: '{text}'")
        
            # Check for divider before Action Items
            if action_items_idx > 0:
                divider_before_action = False
                for i in range(action_items_idx - 1, max(0, action_items_idx - 5), -1):
                    if blocks[i].get("type") == "divider":
                        divider_before_action = True
                        break
                if not divider_before_action:
                    missing.append("divider before Action Items")
        
            if missing:
                errors.append(f"[X] Mid-Sprint Review section missing: {', '.join(missing)}")
            else:
                checks_passed.append(f"[C] Mid-Sprint Review section has")
        
            return TaskScore(
                score=1.0 if len(errors) == 0 else 0.0,
                metadata=ScoreMetadata(
                    success_accumulator=list(dict.fromkeys(checks_passed)),
                    error_accumulator=list(dict.fromkeys(errors)),
                )
            )
    
        except Exception as e:
            errors.append(f"[X] Error validating mid-sprint review section: {str(e)}")
            return TaskScore(
                score=0.0,
                metadata=ScoreMetadata(
                    success_accumulator=list(dict.fromkeys(checks_passed)),
                    error_accumulator=list(dict.fromkeys(errors)),
                )
            )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Validation Functions
# =============================================================================
def _validate_agent_add_action_items_retrospective(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validates action items retrospective with conditional callouts on Sprint Planning page.
    
    Requirements:
    1. Green callouts with ✅ icon after each checked todo saying 'Completed on schedule'
    2. heading_2 '📝 Retrospective Notes' after action items
    3. Bulleted list with total items, completed, success rate
    4. Green celebration callout if 100% success rate
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    try:
        try:
            # Find the Sprint Planning page
            sprint_pages = _get_pages(backend, "Sprint Planning")
            if not sprint_pages:
                errors.append("[X] Sprint Planning page not found")
            else:
                checks_passed.append("[C] Sprint Planning page found")
        
            page = sprint_pages[0]
            page_id = page.get("_id")
            blocks = _get_blocks(backend, page_id)
        
            if not blocks:
                errors.append("[X] Sprint Planning page has no blocks")
            else:
                checks_passed.append("[C] Sprint Planning page has blocks")
        
            missing = []
        
            # Check for 'Completed on schedule' green callouts
            completed_callouts = 0
            for block in blocks:
                if block.get("type") == "callout":
                    content = block.get("content", "")
                    props = block.get("properties", {})
                    if ("Completed on schedule" in content and 
                        props.get("backgroundColor") == "green_background"):
                        completed_callouts += 1
        
            if completed_callouts < 2:
                missing.append(f"green 'Completed on schedule' callouts (found {completed_callouts}, expected 2)")
        
            # Check for Retrospective Notes heading
            retro_found = False
            for block in blocks:
                if block.get("type") == "heading2" and "Retrospective Notes" in block.get("content", ""):
                    retro_found = True
                    break
        
            if not retro_found:
                missing.append("heading_2 '📝 Retrospective Notes'")
        
            # Check for statistics bulleted list
            stats_found = {"total": False, "completed": False, "rate": False}
            for block in blocks:
                if block.get("type") == "bulletedList":
                    content = block.get("content", "")
                    if "Total action items" in content:
                        stats_found["total"] = True
                    if "Completed on time" in content:
                        stats_found["completed"] = True
                    if "Success rate" in content:
                        stats_found["rate"] = True
        
            if not stats_found["total"]:
                missing.append("bulleted list with total action items")
            if not stats_found["completed"]:
                missing.append("bulleted list with completed count")
            if not stats_found["rate"]:
                missing.append("bulleted list with success rate")
        
            # Check for celebration callout (100% success rate means green callout)
            celebration_found = False
            for block in blocks:
                if block.get("type") == "callout":
                    content = block.get("content", "")
                    props = block.get("properties", {})
                    if ("Perfect execution" in content and 
                        props.get("backgroundColor") == "green_background"):
                        celebration_found = True
                        break
        
            if not celebration_found:
                missing.append("green celebration callout for 100% completion")
        
            if missing:
                errors.append(f"[X] Action items retrospective missing: {', '.join(missing)}")
            else:
                checks_passed.append(f"[C] Action items retrospective has")
        
            return TaskScore(
                score=1.0 if len(errors) == 0 else 0.0,
                metadata=ScoreMetadata(
                    success_accumulator=list(dict.fromkeys(checks_passed)),
                    error_accumulator=list(dict.fromkeys(errors)),
                )
            )
    
        except Exception as e:
            errors.append(f"[X] Error validating action items retrospective: {str(e)}")
            return TaskScore(
                score=0.0,
                metadata=ScoreMetadata(
                    success_accumulator=list(dict.fromkeys(checks_passed)),
                    error_accumulator=list(dict.fromkeys(errors)),
                )
            )

    # -----------------------------------------------------------------------------
    # enhance-onboarding-experience-v2
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_enhance_onboarding_experience(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validates enhanced onboarding experience on Getting Started page.
    
    Requirements:
    1. Blue callout with 🎯 icon after Quick Start heading
    2. Hint paragraphs below unchecked todos (italic gray text)
    3. Completion Reward section with heading_3 and paragraph
    4. Progress counter at the end
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    try:
        try:
            # Find the Getting Started page
            gs_pages = _get_pages(backend, "Getting Started")
            if not gs_pages:
                errors.append("[X] Getting Started page not found")
            else:
                checks_passed.append("[C] Getting Started page found")
        
            page = gs_pages[0]
            page_id = page.get("_id")
            blocks = _get_blocks(backend, page_id)
        
            if not blocks:
                errors.append("[X] Getting Started page has no blocks")
            else:
                checks_passed.append("[C] Getting Started page has blocks")
        
            missing = []
        
            # Check for blue callout with 🎯 icon containing onboarding text
            callout_found = False
            for block in blocks:
                if block.get("type") == "callout":
                    props = block.get("properties", {})
                    content = block.get("content", "")
                    if (props.get("backgroundColor") == "blue_background" and
                        "Complete these steps" in content):
                        callout_found = True
                        break
        
            if not callout_found:
                missing.append("blue callout with onboarding instructions")
        
            # Check for hint paragraphs
            hint_block_types = False
            hint_share = False
            for block in blocks:
                if block.get("type") == "paragraph":
                    content = block.get("content", "")
                    if "Hint" in content and "block types" in content.lower():
                        hint_block_types = True
                    if "Hint" in content and "Share" in content:
                        hint_share = True
        
            if not hint_block_types:
                missing.append("hint paragraph for 'Try different block types'")
            if not hint_share:
                missing.append("hint paragraph for 'Share a page'")
        
            # Check for Completion Reward section
            reward_heading = False
            reward_paragraph = False
            for block in blocks:
                if block.get("type") == "heading3" and "Completion Reward" in block.get("content", ""):
                    reward_heading = True
                if block.get("type") == "paragraph" and "advanced templates" in block.get("content", "").lower():
                    reward_paragraph = True
        
            if not reward_heading:
                missing.append("heading_3 '🏆 Completion Reward'")
            if not reward_paragraph:
                missing.append("paragraph about advanced templates library")
        
            # Check for divider before Completion Reward
            divider_found = any(b.get("type") == "divider" for b in blocks)
            if not divider_found:
                missing.append("divider before Completion Reward")
        
            # Check for progress counter
            progress_found = False
            for block in blocks:
                content = block.get("content", "")
                if "Progress:" in content and "tasks completed" in content:
                    progress_found = True
                    break
        
            if not progress_found:
                missing.append("progress counter at the end")
        
            if missing:
                errors.append(f"[X] Onboarding experience enhancements missing: {', '.join(missing)}")
            else:
                checks_passed.append(f"[C] Onboarding experience enhancements has")
        
            return TaskScore(
                score=1.0 if len(errors) == 0 else 0.0,
                metadata=ScoreMetadata(
                    success_accumulator=list(dict.fromkeys(checks_passed)),
                    error_accumulator=list(dict.fromkeys(errors)),
                )
            )
    
        except Exception as e:
            errors.append(f"[X] Error validating onboarding experience: {str(e)}")
            return TaskScore(
                score=0.0,
                metadata=ScoreMetadata(
                    success_accumulator=list(dict.fromkeys(checks_passed)),
                    error_accumulator=list(dict.fromkeys(errors)),
                )
            )

    # -----------------------------------------------------------------------------
    # reorganize-standup-template-v2
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_reorganize_standup_template(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validates reorganized Weekly Standup Template page.
    
    Requirements:
    1. Blockers section moved after 'What I did this week'
    2. Metrics & KPIs section at original Blockers position with purple callout
    3. Summary paragraph at end with accurate todo and section counts
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    try:
        try:
            # Find the Weekly Standup Template page
            template_pages = _get_pages(backend, "Weekly Standup Template")
            if not template_pages:
                errors.append("[X] Weekly Standup Template page not found")
            else:
                checks_passed.append("[C] Weekly Standup Template page found")
        
            page = template_pages[0]
            page_id = page.get("_id")
            blocks = _get_blocks(backend, page_id)
        
            if not blocks:
                errors.append("[X] Weekly Standup Template page has no blocks")
            else:
                checks_passed.append("[C] Weekly Standup Template page has blocks")
        
            missing = []
        
            # Find positions of key headings
            what_i_did_idx = -1
            blockers_idx = -1
            what_i_plan_idx = -1
            metrics_idx = -1
        
            for i, block in enumerate(blocks):
                if block.get("type") == "heading2":
                    content = block.get("content", "")
                    if "What I did this week" in content:
                        what_i_did_idx = i
                    elif "Blockers" in content:
                        blockers_idx = i
                    elif "What I plan to do next week" in content:
                        what_i_plan_idx = i
                    elif "Metrics & KPIs" in content:
                        metrics_idx = i
        
            # Check that Blockers comes after "What I did this week" and before "What I plan to do next week"
            if what_i_did_idx == -1:
                missing.append("'What I did this week' heading")
            if blockers_idx == -1:
                missing.append("'Blockers' heading")
            if what_i_plan_idx == -1:
                missing.append("'What I plan to do next week' heading")
        
            if what_i_did_idx != -1 and blockers_idx != -1 and what_i_plan_idx != -1:
                if not (what_i_did_idx < blockers_idx < what_i_plan_idx):
                    missing.append("Blockers section should be between 'What I did this week' and 'What I plan to do next week'")
        
            # Check for Metrics & KPIs section
            if metrics_idx == -1:
                missing.append("heading_2 '📈 Metrics & KPIs'")
        
            # Check for purple callout with KPIs text
            purple_callout = False
            for block in blocks:
                if block.get("type") == "callout":
                    props = block.get("properties", {})
                    content = block.get("content", "")
                    if (props.get("backgroundColor") == "purple_background" and
                        "KPIs" in content):
                        purple_callout = True
                        break
        
            if not purple_callout:
                missing.append("purple callout with KPIs text")
        
            # Check for bullet points
            bullet_texts = ["Code commits", "Pull requests reviewed", "Tickets completed"]
            for text in bullet_texts:
                found = any(b.get("type") == "bulletedList" and text in b.get("content", "") 
                           for b in blocks)
                if not found:
                    missing.append(f"bulletedList with '{text}'")
        
            # Check for summary paragraph
            summary_found = False
            for block in blocks:
                if block.get("type") == "paragraph":
                    content = block.get("content", "")
                    if "template contains" in content and "task items" in content and "sections" in content:
                        summary_found = True
                        break
        
            if not summary_found:
                missing.append("summary paragraph with todo and section counts")
        
            # Check for divider before summary
            divider_found = any(b.get("type") == "divider" for b in blocks)
            if not divider_found:
                missing.append("divider before summary")
        
            if missing:
                errors.append(f"[X] Standup template reorganization missing: {', '.join(missing)}")
            else:
                checks_passed.append(f"[C] Standup template reorganization has")
        
            return TaskScore(
                score=1.0 if len(errors) == 0 else 0.0,
                metadata=ScoreMetadata(
                    success_accumulator=list(dict.fromkeys(checks_passed)),
                    error_accumulator=list(dict.fromkeys(errors)),
                )
            )
    
        except Exception as e:
            errors.append(f"[X] Error validating standup template: {str(e)}")
            return TaskScore(
                score=0.0,
                metadata=ScoreMetadata(
                    success_accumulator=list(dict.fromkeys(checks_passed)),
                    error_accumulator=list(dict.fromkeys(errors)),
                )
            )

    # -----------------------------------------------------------------------------
    # add-product-team-section-v2
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_add_product_team_section(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validates Product Team section addition to Team Directory.
    
    Requirements:
    1. Team Directory page has 'Product Team' heading_2
    2. Product Team appears AFTER Engineering Team (Frank Zhang) and BEFORE Design Team
    3. Contains exactly 3 team members: Grace Liu, Henry Park, Isabella Chen
    4. Team Photo image is the last block on the page
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    try:
        try:
            team_dir_pages = _get_pages(backend, "Team Directory")
            if not team_dir_pages:
                errors.append("[X] Team Directory page not found")
            else:
                checks_passed.append("[C] Team Directory page found")
        
            page = team_dir_pages[0]
            page_id = page.get("_id")
            blocks = _get_blocks(backend, page_id)
        
            if not blocks:
                errors.append("[X] Team Directory page has no blocks")
            else:
                checks_passed.append("[C] Team Directory page has blocks")
        
            missing = []
        
            # Find key positions
            engineering_team_idx = None
            product_team_idx = None
            design_team_idx = None
            frank_zhang_idx = None
        
            for i, block in enumerate(blocks):
                content = block.get("content", "")
                block_type = block.get("type", "")
            
                if block_type == "heading2" and "Engineering Team" in content:
                    engineering_team_idx = i
                elif block_type == "heading2" and "Product Team" in content:
                    product_team_idx = i
                elif block_type == "heading2" and "Design Team" in content:
                    design_team_idx = i
                elif block_type == "bulletedList" and "Frank Zhang" in content:
                    frank_zhang_idx = i
        
            # Check Product Team exists
            if product_team_idx is None:
                missing.append("heading_2 'Product Team'")
        
            # Check positioning: Product Team should be after Engineering (Frank Zhang) and before Design
            if product_team_idx is not None and frank_zhang_idx is not None and design_team_idx is not None:
                if not (frank_zhang_idx < product_team_idx < design_team_idx):
                    missing.append("Product Team not positioned between Engineering and Design teams")
        
            # Check for the three team members
            team_members = ["Grace Liu", "Henry Park", "Isabella Chen"]
            for member in team_members:
                found = any(
                    b.get("type") == "bulletedList" and member in b.get("content", "")
                    for b in blocks
                )
                if not found:
                    missing.append(f"bulletedList for {member}")
        
            # Check Team Photo is the last block
            last_block = blocks[-1] if blocks else None
            if last_block:
                if last_block.get("type") != "image" or "Team Photo" not in last_block.get("content", ""):
                    # Check if it's the last non-trivial block
                    found_image_at_end = False
                    for i in range(len(blocks) - 1, -1, -1):
                        if blocks[i].get("type") == "image" and "Team Photo" in blocks[i].get("content", ""):
                            # Check if all blocks after it are trivial (divider, empty)
                            all_trivial_after = True
                            for j in range(i + 1, len(blocks)):
                                if blocks[j].get("type") not in ["divider"] and blocks[j].get("content", "").strip():
                                    all_trivial_after = False
                                    break
                            if all_trivial_after or i == len(blocks) - 1:
                                found_image_at_end = True
                            break
                
                    if not found_image_at_end:
                        missing.append("Team Photo image not at the end of the page")
            else:
                missing.append("Team Photo image not found")
        
            if missing:
                errors.append(f"[X] Product Team section missing: {', '.join(missing)}")
            else:
                checks_passed.append(f"[C] Product Team section has")
        
            return TaskScore(
                score=1.0 if len(errors) == 0 else 0.0,
                metadata=ScoreMetadata(
                    success_accumulator=list(dict.fromkeys(checks_passed)),
                    error_accumulator=list(dict.fromkeys(errors)),
                )
            )
    
        except Exception as e:
            errors.append(f"[X] Error validating Product Team section: {str(e)}")
            return TaskScore(
                score=0.0,
                metadata=ScoreMetadata(
                    success_accumulator=list(dict.fromkeys(checks_passed)),
                    error_accumulator=list(dict.fromkeys(errors)),
                )
            )

    # -----------------------------------------------------------------------------
    # swap-wiki-sections-with-additions-v2
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_swap_wiki_sections_with_additions(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validates swapping Tech Stack and Development Setup sections in Engineering Wiki.
    
    Requirements:
    1. Development Setup section appears BEFORE Tech Stack section
    2. Red callout with ⚠️ appears after 'Environment Variables' heading
    3. Bookmark to stackshare.io appears after Tech Stack heading
    4. Divider and quote at the very end of the page
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    try:
        try:
            wiki_pages = _get_pages(backend, "Engineering Wiki")
            if not wiki_pages:
                errors.append("[X] Engineering Wiki page not found")
            else:
                checks_passed.append("[C] Engineering Wiki page found")
        
            page = wiki_pages[0]
            page_id = page.get("_id")
            blocks = _get_blocks(backend, page_id)
        
            if not blocks:
                errors.append("[X] Engineering Wiki page has no blocks")
            else:
                checks_passed.append("[C] Engineering Wiki page has blocks")
        
            missing = []
        
            # Find key positions
            tech_stack_idx = None
            dev_setup_idx = None
            env_vars_idx = None
        
            for i, block in enumerate(blocks):
                content = block.get("content", "")
                block_type = block.get("type", "")
            
                if block_type == "heading2" and "Tech Stack" in content:
                    tech_stack_idx = i
                elif block_type == "heading2" and "Development Setup" in content:
                    dev_setup_idx = i
                elif block_type == "heading3" and "Environment Variables" in content:
                    env_vars_idx = i
        
            # 1. Check Development Setup comes before Tech Stack
            if dev_setup_idx is None:
                missing.append("heading_2 'Development Setup' not found")
            if tech_stack_idx is None:
                missing.append("heading_2 'Tech Stack' not found")
        
            if dev_setup_idx is not None and tech_stack_idx is not None:
                if dev_setup_idx >= tech_stack_idx:
                    missing.append("Development Setup should appear BEFORE Tech Stack (sections not swapped)")
        
            # 2. Check red callout after Environment Variables
            if env_vars_idx is not None:
                next_idx = env_vars_idx + 1
                if next_idx < len(blocks):
                    next_block = blocks[next_idx]
                    if (next_block.get("type") != "callout" or
                        next_block.get("properties", {}).get("backgroundColor") != "red_background" or
                        next_block.get("properties", {}).get("icon") != "⚠️" or
                        "Never commit .env files" not in next_block.get("content", "")):
                        missing.append("Red callout with ⚠️ about .env files not found after Environment Variables")
                else:
                    missing.append("Red callout missing after Environment Variables")
            else:
                missing.append("heading_3 'Environment Variables' not found")
        
            # 3. Check bookmark after Tech Stack heading
            if tech_stack_idx is not None:
                next_idx = tech_stack_idx + 1
                if next_idx < len(blocks):
                    next_block = blocks[next_idx]
                    if (next_block.get("type") != "bookmark" or
                        "stackshare.io" not in next_block.get("properties", {}).get("url", "")):
                        missing.append("Bookmark to stackshare.io not found after Tech Stack heading")
                else:
                    missing.append("Bookmark missing after Tech Stack heading")
        
            # 4. Check divider and quote at the end
            if len(blocks) >= 2:
                second_to_last = blocks[-2]
                last_block = blocks[-1]
            
                if second_to_last.get("type") != "divider":
                    missing.append("Divider not found at second-to-last position")
            
                if (last_block.get("type") != "quote" or 
                    "Good documentation is as important as good code" not in last_block.get("content", "")):
                    missing.append("Quote block with expected text not found at the end")
            else:
                missing.append("Page too short to have divider and quote at end")
        
            if missing:
                errors.append(f"[X] Wiki sections swap validation failed: {', '.join(missing)}")
            else:
                checks_passed.append(f"[C] Wiki sections swap validation succeeded")
        
            return TaskScore(
                score=1.0 if len(errors) == 0 else 0.0,
                metadata=ScoreMetadata(
                    success_accumulator=list(dict.fromkeys(checks_passed)),
                    error_accumulator=list(dict.fromkeys(errors)),
                )
            )
    
        except Exception as e:
            errors.append(f"[X] Error validating wiki sections swap: {str(e)}")
            return TaskScore(
                score=0.0,
                metadata=ScoreMetadata(
                    success_accumulator=list(dict.fromkeys(checks_passed)),
                    error_accumulator=list(dict.fromkeys(errors)),
                )
            )

    # -----------------------------------------------------------------------------
    # create-external-resources-audit-v2
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_create_external_resources_audit(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validates External Resources Audit page creation.
    
    Requirements:
    1. Page exists as child of Engineering Wiki
    2. Contains heading_1 '🔍 External Resources Audit'
    3. Contains heading_2 '📊 Resource Distribution'
    4. For each section: heading_3 '[Section Name] Analysis', paragraph with count, numbered list
    5. heading_2 '⚠️ Duplicate Detection' with bulleted list of duplicate URLs
    6. heading_2 '📈 Recommendations' with orange callout
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    try:
        try:
            # Find the audit page by querying all pages
            all_pages_result = backend.query({"collection": "pages", "filter": {}})
            all_pages = all_pages_result if isinstance(all_pages_result, list) else []
        
            audit_pages = [p for p in all_pages if "External Resources Audit" in p.get("title", "") or "Resources Audit" in p.get("title", "")]
            if not audit_pages:
                errors.append("[X] External Resources Audit page not found")
            else:
                checks_passed.append("[C] External Resources Audit page found")
        
            page = audit_pages[0]
            page_id = page.get("_id")
        
            # Check parent is Engineering Wiki
            parent_id = page.get("parentId") or page.get("parent_id")
            if parent_id:
                wiki_pages = _get_pages(backend, "Engineering Wiki")
                if wiki_pages:
                    wiki_id = wiki_pages[0].get("_id")
                    if parent_id != wiki_id:
                        errors.append("[X] External Resources Audit page is not a child of Engineering Wiki")
                    else:
                        checks_passed.append("[C] External Resources Audit page is a child of Engineering Wiki")
                else:
                    errors.append("[X] Engineering Wiki page not found")
            else:
                errors.append("[X] External Resources Audit page has no parent (should be child of Engineering Wiki)")
        
            blocks = _get_blocks(backend, page_id)
        
            if not blocks:
                errors.append("[X] External Resources Audit page has no blocks")
            else:
                checks_passed.append("[C] External Resources Audit page has blocks")
        
            missing = []
        
            # Check for main heading
            main_heading = any(
                b.get("type") == "heading1" and "External Resources Audit" in b.get("content", "")
                for b in blocks
            )
            if not main_heading:
                missing.append("heading_1 '🔍 External Resources Audit'")
        
            # Check for Resource Distribution heading
            resource_dist = any(
                b.get("type") == "heading2" and "Resource Distribution" in b.get("content", "")
                for b in blocks
            )
            if not resource_dist:
                missing.append("heading_2 '📊 Resource Distribution'")
        
            # Check for section analysis headings (heading_3 with 'Analysis')
            analysis_headings = [
                b for b in blocks
                if b.get("type") == "heading3" and "Analysis" in b.get("content", "")
            ]
            if len(analysis_headings) < 1:
                missing.append("heading_3 section analysis entries")
        
            # Check for 'Total resources:' paragraphs
            total_resources_found = any(
                b.get("type") == "paragraph" and "Total resources:" in b.get("content", "")
                for b in blocks
            )
            if not total_resources_found:
                missing.append("paragraph with 'Total resources:' count")
        
            # Check for numbered list (bookmark listings)
            numbered_list_found = any(b.get("type") == "numberedList" for b in blocks)
            if not numbered_list_found:
                missing.append("numbered list with bookmark listings")
        
            # Check for Duplicate Detection heading
            duplicate_detection = any(
                b.get("type") == "heading2" and "Duplicate Detection" in b.get("content", "")
                for b in blocks
            )
            if not duplicate_detection:
                missing.append("heading_2 '⚠️ Duplicate Detection'")
        
            # Check for bulleted list (duplicates)
            bulleted_list_found = any(b.get("type") == "bulletedList" for b in blocks)
            if not bulleted_list_found:
                missing.append("bulleted list with duplicate URLs")
        
            # Check for Recommendations heading
            recommendations = any(
                b.get("type") == "heading2" and "Recommendations" in b.get("content", "")
                for b in blocks
            )
            if not recommendations:
                missing.append("heading_2 '📈 Recommendations'")
        
            # Check for orange callout with recommendations
            orange_callout = any(
                b.get("type") == "callout" and
                b.get("properties", {}).get("backgroundColor") == "orange_background" and
                "consolidating" in b.get("content", "").lower()
                for b in blocks
            )
            if not orange_callout:
                missing.append("orange callout with recommendations text")
        
            if missing:
                errors.append(f"[X] External Resources Audit page missing: {', '.join(missing)}")
            else:
                checks_passed.append(f"[C] External Resources Audit page has")
        
            return TaskScore(
                score=1.0 if len(errors) == 0 else 0.0,
                metadata=ScoreMetadata(
                    success_accumulator=list(dict.fromkeys(checks_passed)),
                    error_accumulator=list(dict.fromkeys(errors)),
                )
            )
    
        except Exception as e:
            errors.append(f"[X] Error validating External Resources Audit: {str(e)}")
            return TaskScore(
                score=0.0,
                metadata=ScoreMetadata(
                    success_accumulator=list(dict.fromkeys(checks_passed)),
                    error_accumulator=list(dict.fromkeys(errors)),
                )
            )

    # -----------------------------------------------------------------------------
    # create-resource-library-hub-v2
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_create_resource_library_hub(
    backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validates Resource Library Hub page creation with catalogued bookmarks.
    
    Requirements:
    1. Page 'Resource Library Hub' exists at root level
    2. Contains heading_1 '📚 Centralized Resource Library'
    3. heading_3 entries for React, TypeScript, Node.js with URL/Description paragraphs
    4. heading_2 '🔗 Quick Access Links' with numbered list
    5. Gray callout with resource count and date
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    try:
        try:
            # Find the Resource Library Hub page by querying all pages and filtering
            all_pages_result = backend.query({"collection": "pages", "filter": {}})
            all_pages = all_pages_result if isinstance(all_pages_result, list) else []
        
            hub_pages = [p for p in all_pages if "Resource Library" in p.get("title", "") or "Centralized Resource" in p.get("title", "")]
            if not hub_pages:
                errors.append("[X] Resource Library Hub page not found")
            else:
                checks_passed.append("[C] Resource Library Hub page found")
        
            page = hub_pages[0]
            page_id = page.get("_id")
            blocks = _get_blocks(backend, page_id)
        
            if not blocks:
                errors.append("[X] Resource Library Hub page has no blocks")
            else:
                checks_passed.append("[C] Resource Library Hub page has blocks")
        
            missing = []
        
            # Check for main heading
            main_heading = False
            for block in blocks:
                if block.get("type") == "heading1" and "Centralized Resource Library" in block.get("content", ""):
                    main_heading = True
                    break
        
            if not main_heading:
                missing.append("heading_1 '📚 Centralized Resource Library'")
        
            # Check for resource headings (React, TypeScript, Node.js)
            resources = ["React", "TypeScript", "Node"]
            for resource in resources:
                found = False
                for block in blocks:
                    if block.get("type") == "heading3" and resource in block.get("content", ""):
                        found = True
                        break
                if not found:
                    missing.append(f"heading_3 for {resource}")
        
            # Check for URL paragraphs
            url_found = False
            for block in blocks:
                if block.get("type") == "paragraph" and "URL:" in block.get("content", ""):
                    url_found = True
                    break
        
            if not url_found:
                missing.append("paragraph with URL information")
        
            # Check for Quick Access Links section
            quick_access_found = False
            for block in blocks:
                if block.get("type") == "heading2" and "Quick Access Links" in block.get("content", ""):
                    quick_access_found = True
                    break
        
            if not quick_access_found:
                missing.append("heading_2 '🔗 Quick Access Links'")
        
            # Check for numbered list
            numbered_list_found = any(b.get("type") == "numberedList" for b in blocks)
            if not numbered_list_found:
                missing.append("numbered list with resources")
        
            # Check for gray callout with resource count
            callout_found = False
            for block in blocks:
                if block.get("type") == "callout":
                    props = block.get("properties", {})
                    content = block.get("content", "")
                    if (props.get("backgroundColor") == "gray_background" and
                        "Total resources catalogued" in content):
                        callout_found = True
                        break
        
            if not callout_found:
                missing.append("gray callout with resource count")
        
            # Check for divider
            divider_found = any(b.get("type") == "divider" for b in blocks)
            if not divider_found:
                missing.append("divider before Quick Access Links")
        
            if missing:
                errors.append(f"[X] Resource Library Hub missing: {', '.join(missing)}")
            else:
                checks_passed.append(f"[C] Resource Library Hub has")
        
            return TaskScore(
                score=1.0 if len(errors) == 0 else 0.0,
                metadata=ScoreMetadata(
                    success_accumulator=list(dict.fromkeys(checks_passed)),
                    error_accumulator=list(dict.fromkeys(errors)),
                )
            )
    
        except Exception as e:
            errors.append(f"[X] Error validating resource library hub: {str(e)}")
            return TaskScore(
                score=0.0,
                metadata=ScoreMetadata(
                    success_accumulator=list(dict.fromkeys(checks_passed)),
                    error_accumulator=list(dict.fromkeys(errors)),
                )
            )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# ============================================================================
# Functions migrated from generated_reward_functions.py
# ============================================================================
def _validate_documentation_hub_creation(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate comprehensive documentation hub creation with sections and content."""
    errors: list[str] = []

    checks_passed = []

    # Check for Documentation Center page
    try:
        doc_center = _find_page_by_title(final_state_backend, "Documentation Center")
        if not doc_center:
            errors.append("[X] Documentation Center page not found")
        else:
            checks_passed.append("[C] Documentation Center page found")

        # Check for books icon
        icon = doc_center.get("icon", "")
        if "book" not in icon.lower() and "📚" not in icon and "📖" not in icon:
            errors.append("[X] Documentation Center does not have a books icon")
        else:
            checks_passed.append("[C] Documentation Center created with books icon")

        # Check if marked as favorite
        if not doc_center.get("isFavorite", False):
            errors.append(f"[X] Documentation Center is not marked as favorite")
        else:
            checks_passed.append("[C] Documentation Center marked as favorite")

        doc_center_id = doc_center.get("_id")
        child_pages = _get_child_pages(final_state_backend, doc_center_id)

        # Check for 3 main sections
        required_sections = ["Technical Docs", "Process Guides", "Quick References"]
        found_sections = []
        section_pages = {}

        for section_name in required_sections:
            section_page = _find_child_by_title(final_state_backend, doc_center, section_name)
            if section_page:
                found_sections.append(section_name)
                section_pages[section_name] = section_page

        if len(found_sections) < 3:
            errors.append(f"[X] Expected 3 main sections, found {len(found_sections)}: {', '.join(found_sections)}")
        else:
            checks_passed.append(f"[C] Found all 3 main sections: {', '.join(found_sections)}")

        # Check if API Documentation and Engineering Wiki are moved under Technical Docs
        if "Technical Docs" not in section_pages:
            errors.append("[X] Technical Docs section not found")
        else:
            checks_passed.append("[C] Technical Docs section found")

        tech_docs_id = section_pages["Technical Docs"].get("_id")

        api_doc = _find_page_by_title(final_state_backend, "API Documentation")
        eng_wiki = _find_page_by_title(final_state_backend, "Engineering Wiki")

        if not api_doc or not eng_wiki:
            errors.append(f"[X] Missing existing pages - API Documentation: {api_doc is not None}, Engineering Wiki: {eng_wiki is not None}")
        else:
            checks_passed.append(f"[C] has existing pages - API Documentation: {api_doc is None}, Engineering Wiki: {eng_wiki is None}")

        api_under_tech = api_doc.get("parentId") == tech_docs_id
        wiki_under_tech = eng_wiki.get("parentId") == tech_docs_id

        if not (api_under_tech and wiki_under_tech):
            errors.append(f"[X] API Documentation and Engineering Wiki not properly moved under Technical Docs (API: {api_under_tech}, Wiki: {wiki_under_tech})")
        else:
            checks_passed.append(f"[C] API Documentation and Engineering Wiki properly moved under Technical Docs (API: {api_under_tech}, Wiki: {wiki_under_tech})")

        checks_passed.append("[C] API Documentation and Engineering Wiki moved under Technical Docs")

        # Check Process Guides content structure
        if "Process Guides" not in section_pages:
            errors.append("[X] Process Guides section not found")
        else:
            checks_passed.append("[C] Process Guides section found")

        process_guides_id = section_pages["Process Guides"].get("_id")
        process_blocks = _get_blocks_for_page(final_state_backend, process_guides_id)

        # Check for numbered lists and callouts
        has_numbered_list = any(block.get("type") == "numberedList" for block in process_blocks)
        has_callout = any(block.get("type") == "callout" for block in process_blocks)

        if not (has_numbered_list and has_callout):
            errors.append(f"[X] Process Guides missing required content structure (numbered lists: {has_numbered_list}, callouts: {has_callout})")
        else:
            checks_passed.append(f"[C] Process Guides has required content structure (numbered lists: {has_numbered_list}, callouts: {has_callout})")

        checks_passed.append("[C] Process Guides has structured content with numbered lists and callouts")

        # Check Quick References content
        if "Quick References" not in section_pages:
            errors.append("[X] Quick References section not found")
        else:
            checks_passed.append("[C] Quick References section found")

        quick_ref_id = section_pages["Quick References"].get("_id")
        quick_ref_blocks = _get_blocks_for_page(final_state_backend, quick_ref_id)

        # Check for some content (should have blocks)
        if len(quick_ref_blocks) < 2:
            errors.append(f"[X] Quick References page lacks sufficient content ({len(quick_ref_blocks)} blocks)")
        else:
            checks_passed.append(f"[C] Quick References page lacks sufficient content ({len(quick_ref_blocks)} blocks)")

        checks_passed.append("[C] Quick References page has content")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_project_tracking_system(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate comprehensive project tracking system creation."""
    errors: list[str] = []

    checks_passed = []

    # Check for Project Hub page existence and properties
    try:
        hub = _find_page_by_title(final_state_backend, "Project Hub")
        if not hub:
            errors.append("[X] Project Hub page not found")
        else:
            checks_passed.append("[C] Project Hub page found")

        # Check for folder icon
        icon = hub.get("icon", "")
        if "folder" not in icon.lower() and "📁" not in icon and "📂" not in icon:
            errors.append("[X] Project Hub does not have a folder icon")
        else:
            checks_passed.append("[C] Project Hub created with folder icon")

        # Check if marked as favorite
        if not hub.get("isFavorite", False):
            errors.append("[X] Project Hub is not marked as favorite")
        else:
            checks_passed.append("[C] Project Hub marked as favorite")

        # Get blocks for Project Hub to check sections
        hub_id = hub.get("_id")
        hub_blocks = _get_blocks_for_page(final_state_backend, hub_id)
    
        # Check for the three main sections as headings
        required_sections = ["Active Projects", "Project Templates", "Archived Projects"]
        found_sections = []
        for block in hub_blocks:
            if block.get("type") in ["heading1", "heading2", "heading3"]:
                content = block.get("content", "")
                for section in required_sections:
                    if section.lower() in content.lower():
                        found_sections.append(section)
    
        if len(found_sections) < 3:
            errors.append(f"[X] Expected 3 main sections (Active Projects, Project Templates, Archived Projects), found {len(found_sections)}")
        else:
            checks_passed.append("[C] Found all 3 main sections")

        # Find the Active Projects section to check if it has the required child pages
        active_projects_children = _get_child_pages(final_state_backend, hub_id)
    
        # Look for Active Projects sub-page or section that contains the moved pages
        active_projects_page = None
        for child in active_projects_children:
            title = child.get("title", "").lower()
            if "active projects" in title or "active" in title:
                active_projects_page = child
                break
    
        # If no Active Projects sub-page exists, check if Project Roadmap and Documentation are direct children of hub
        # positioned after the Active Projects heading in the blocks structure
        roadmap = _find_page_by_title(final_state_backend, "Project Roadmap")
        if not roadmap:
            errors.append("[X] Project Roadmap page not found")
        else:
            checks_passed.append("[C] Project Roadmap page found")
    
        doc = _find_page_by_title(final_state_backend, "Project Documentation")
        if not doc:
            errors.append("[X] Project Documentation page not found")
        else:
            checks_passed.append("[C] Project Documentation page found")
    
        # Check if they are organized under Active Projects (either as children of Active Projects page or as children of Project Hub)
        roadmap_properly_placed = False
        doc_properly_placed = False
    
        if active_projects_page:
            # If there's an Active Projects sub-page, check if they are children of it
            active_projects_id = active_projects_page.get("_id")
            if roadmap.get("parentId") == active_projects_id:
                roadmap_properly_placed = True
            if doc.get("parentId") == active_projects_id:
                doc_properly_placed = True
        else:
            # If no Active Projects sub-page, they should be children of Project Hub
            if roadmap.get("parentId") == hub_id:
                roadmap_properly_placed = True
            if doc.get("parentId") == hub_id:
                doc_properly_placed = True
    
        if not roadmap_properly_placed:
            errors.append("[X] Project Roadmap is not properly organized under Active Projects section")
        else:
            checks_passed.append("[C] Project Roadmap is properly organized under Active Projects section")
        if not doc_properly_placed:
            errors.append("[X] Project Documentation is not properly organized under Active Projects section")
        else:
            checks_passed.append("[C] Project Documentation is properly organized under Active Projects section")
    
        checks_passed.append("[C] Project Roadmap and Project Documentation moved under Active Projects")

        # Check for a new project template page (look for pages with "template" in title)
        # Query pages with "template" and "project" in title using regex
        template_pages_result = final_state_backend.query({
            "collection": "pages",
            "filter": {
                "title": {"$regex": "template.*project|project.*template", "$options": "i"}
            }
        })
        template_pages = template_pages_result if isinstance(template_pages_result, list) else []
    
        if not template_pages:
            errors.append("[X] No project template page found")
        else:
            checks_passed.append("[C] project template page found")
    
        # Validate template has structured content (headings and todo items)
        template_found = False
        for template in template_pages:
            template_id = template.get("_id")
            template_blocks = _get_blocks_for_page(final_state_backend, template_id)
        
            has_headings = any(block.get("type") in ["heading1", "heading2", "heading3"] for block in template_blocks)
            has_todos = any(block.get("type") == "todo" for block in template_blocks)
        
            if has_headings and has_todos:
                template_found = True
                checks_passed.append("[C] Project template created with headings and todo items")
                break
    
        if not template_found:
            errors.append("[X] Project template does not contain structured content with headings and todo items")
        else:
            checks_passed.append("[C] Project template does contains structured content with headings and todo items")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_meeting_documentation_restructure(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate meeting documentation structure reorganization."""
    errors: list[str] = []

    checks_passed = []
    
    # Check for Team Meetings 2024 archive page
    try:
        archive_page = _find_page_by_title(final_state_backend, "Team Meetings 2024")
        if not archive_page:
            errors.append("[X] Team Meetings 2024 archive page not found")
        else:
            checks_passed.append("[C] Team Meetings 2024 archive page found")
    
        # Check for calendar icon
        archive_icon = archive_page.get("icon", "")
        if "calendar" not in archive_icon.lower() and "📅" not in archive_icon and "🗓" not in archive_icon and "🗓️" not in archive_icon:
            errors.append("[X] Team Meetings 2024 does not have a calendar icon")
        else:
            checks_passed.append("[C] Team Meetings 2024 created with calendar icon")
    
        # Check if archive page is marked as favorite
        if not archive_page.get("isFavorite", False):
            errors.append("[X] Team Meetings 2024 archive page is not marked as favorite")
        else:
            checks_passed.append("[C] Team Meetings 2024 marked as favorite")
    
        # Check that old meeting notes are moved under archive
        archive_id = archive_page.get("_id")
        archive_children = _get_child_pages(final_state_backend, archive_id)
    
        # Validate that there are moved meeting-related pages under the archive
        if len(archive_children) == 0:
            errors.append("[X] No existing meeting pages found under Team Meetings 2024 archive")
        else:
            checks_passed.append("[C] existing meeting pages found under Team Meetings 2024 archive")
    
        # Check that these children have meeting-related content or were previously meeting pages
        meeting_related_children = 0
        for child in archive_children:
            title_lower = child.get("title", "").lower()
            # Look for meeting-related keywords in titles
            if any(keyword in title_lower for keyword in ["meeting", "sprint", "planning", "retrospective", "standup", "sync", "review"]):
                meeting_related_children += 1
            # Also check if page has meeting-related content in blocks
            else:
                child_blocks = _get_blocks_for_page(final_state_backend, child.get("_id"))
                child_content = " ".join([block.get("content", "") for block in child_blocks]).lower()
                if any(keyword in child_content for keyword in ["meeting", "agenda", "action items", "attendees", "discussion"]):
                    meeting_related_children += 1
    
        if meeting_related_children == 0:
            errors.append("[X] Archive contains pages but none appear to be meeting-related content")
        else:
            checks_passed.append("[C] Archive contains pages but none appear to be meeting-related content")
    
        checks_passed.append(f"[C] Found {len(archive_children)} pages moved under archive, {meeting_related_children} appear meeting-related")
    
        # Check for new Meeting Notes template page (should be separate from archive)
        new_meeting_notes = None
        meeting_notes_pages = _find_pages_by_title(final_state_backend, "Meeting Notes")
    
        # Find the Meeting Notes page that is NOT a child of the archive
        for page in meeting_notes_pages:
            if page.get("parentId") != archive_id:
                new_meeting_notes = page
                break
    
        if not new_meeting_notes:
            errors.append("[X] New Meeting Notes template page not found (should be separate from archive)")
        else:
            checks_passed.append("[C] New Meeting Notes template page found (should be separate from archive)")
    
        # Get blocks for the new Meeting Notes page
        new_notes_id = new_meeting_notes.get("_id")
        new_notes_blocks = _get_blocks_for_page(final_state_backend, new_notes_id)
    
        # Check for required sections: Agenda, Discussion Points, Action Items, Next Steps
        required_sections = ["agenda", "discussion points", "action items", "next steps"]
        found_sections = []
    
        for block in new_notes_blocks:
            content_lower = block.get("content", "").lower()
            block_type = block.get("type")
            if block_type in ["heading1", "heading2", "heading3"]:
                for section in required_sections:
                    if section in content_lower and section not in found_sections:
                        found_sections.append(section)
    
        if len(found_sections) < 4:
            missing_sections = [s for s in required_sections if s not in found_sections]
            errors.append(f"[X] New Meeting Notes template missing required sections: {missing_sections}")
        else:
            checks_passed.append("[C] All 4 required sections found in new Meeting Notes template")
    
        # Check for appropriate block types (headings, lists, todos)
        block_types = [block.get("type") for block in new_notes_blocks]
    
        has_headings = any(t in ["heading1", "heading2", "heading3"] for t in block_types)
        has_lists = any(t in ["bulletedList", "numberedList"] for t in block_types)
        has_todos = "todo" in block_types
    
        if not has_headings:
            errors.append("[X] New Meeting Notes template missing heading blocks")
        else:
            checks_passed.append("[C] New Meeting Notes template has heading blocks")
        if not has_lists:
            errors.append("[X] New Meeting Notes template missing list blocks")
        else:
            checks_passed.append("[C] New Meeting Notes template has list blocks")
        if not has_todos:
            errors.append("[X] New Meeting Notes template missing todo blocks")
        else:
            checks_passed.append("[C] New Meeting Notes template has todo blocks")
    
        checks_passed.append("[C] New Meeting Notes template has appropriate block types (headings, lists, todos)")
    
        # Ensure template has substantial example content
        content_blocks = [b for b in new_notes_blocks if b.get("content", "").strip()]
        if len(content_blocks) < 8:  # Should have section headings plus example content
            errors.append(f"[X] New Meeting Notes template appears to have minimal content, found only {len(content_blocks)} blocks with content")
        else:
            checks_passed.append(f"[C] New Meeting Notes template appears to have minimal content, found only {len(content_blocks)} blocks with content")
    
        checks_passed.append(f"[C] New Meeting Notes template has example content ({len(content_blocks)} content blocks)")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_onboarding_checklist_creation(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate creation of New Hire Onboarding Checklist from Weekly Standup Template."""
    errors: list[str] = []

    checks_passed = []
    
    # Check that original Weekly Standup Template still exists unchanged
    try:
        original_template = _find_page_by_title(final_state_backend, "Weekly Standup Template")
        if not original_template:
            errors.append("[X] Original 'Weekly Standup Template' page was not found or was deleted")
        else:
            checks_passed.append("[C] Original 'Weekly Standup Template' page was found or was deleted")
    
        if original_template.get("icon") != "📋" or not original_template.get("isFavorite"):
            errors.append("[X] Original 'Weekly Standup Template' properties were modified")
        else:
            checks_passed.append("[C] Original Weekly Standup Template remains unchanged")
    
        # Check for New Hire Onboarding Checklist page
        onboarding_page = _find_page_by_title(final_state_backend, "New Hire Onboarding Checklist")
        if not onboarding_page:
            errors.append("[X] 'New Hire Onboarding Checklist' page not found")
        else:
            checks_passed.append("[C] New Hire Onboarding Checklist page created")
    
        # Check for graduation cap icon
        icon = onboarding_page.get("icon", "")
        if "🎓" not in icon and "graduation" not in icon.lower():
            errors.append("[X] New Hire Onboarding Checklist does not have a graduation cap icon")
        else:
            checks_passed.append("[C] Graduation cap icon set")
    
        # Check if page is marked as favorite
        if not onboarding_page.get("isFavorite"):
            errors.append("[X] New Hire Onboarding Checklist is not marked as favorite")
        else:
            checks_passed.append("[C] Page marked as favorite")
    
        # Check if page is under Team Directory
        team_directory = _find_page_by_title(final_state_backend, "Team Directory")
        if not team_directory:
            errors.append("[X] Team Directory page not found")
        else:
            checks_passed.append("[C] Team Directory page found")
    
        if onboarding_page.get("parentId") != team_directory.get("_id"):
            errors.append("[X] New Hire Onboarding Checklist is not a child of Team Directory")
        else:
            checks_passed.append("[C] Page moved under Team Directory")
    
        # Check content structure and block types
        onboarding_id = onboarding_page.get("_id")
        page_blocks = _get_blocks_for_page(final_state_backend, onboarding_id)
    
        if len(page_blocks) < 5:
            errors.append(f"[X] Expected comprehensive content, found only {len(page_blocks)} blocks")
        else:
            checks_passed.append(f"[C] Expected comprehensive content, found only {len(page_blocks)} blocks")
    
        # Check for required block types
        block_types = [block.get("type") for block in page_blocks]
        required_types = ["heading1", "callout", "todo", "bookmark"]
        missing_types = []
    
        # Check for headings (heading1, heading2, or heading3)
        if not any(t in block_types for t in ["heading1", "heading2", "heading3"]):
            missing_types.append("headings")
    
        # Check for callouts
        if "callout" not in block_types:
            missing_types.append("callouts")
    
        # Check for todo items
        if "todo" not in block_types:
            missing_types.append("todo items")
    
        # Check for bookmarks
        if "bookmark" not in block_types:
            missing_types.append("bookmarks")
    
        if missing_types:
            errors.append(f"[X] Missing required content types: {', '.join(missing_types)}")
        else:
            checks_passed.append(f"[C] has required content types: {', '.join(missing_types)}")
    
        checks_passed.append("[C] Content includes required block types (headings, callouts, todos, bookmarks)")
    
        # Additional validation: check for multiple headings for organization
        heading_count = sum(1 for t in block_types if t in ["heading1", "heading2", "heading3"])
        if heading_count < 2:
            errors.append("[X] Expected multiple headings for proper organization")
        else:
            checks_passed.append(f"[C] Well-organized with {heading_count} headings")
    
        # Additional validation: check for multiple todos
        todo_count = block_types.count("todo")
        if todo_count < 2:
            errors.append("[X] Expected multiple todo items for checklist functionality")
        else:
            checks_passed.append(f"[C] Contains {todo_count} todo items")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_archive_organization(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate creation of Archive 2024 page with proper organization of archived content."""
    errors: list[str] = []

    checks_passed = []

    # Check for Archive 2024 page
    try:
        archive_page = _find_page_by_title(final_state_backend, "Archive 2024")
        if not archive_page:
            errors.append("[X] Archive 2024 page not found")
        else:
            checks_passed.append("[C] Archive 2024 page found")

        # Check for folder icon
        icon = archive_page.get("icon", "")
        if "folder" not in icon.lower() and "📁" not in icon and "📂" not in icon:
            errors.append("[X] Archive 2024 page does not have a folder icon")
        else:
            checks_passed.append("[C] Archive 2024 created with folder icon")

        # Check if marked as favorite
        if not archive_page.get("isFavorite", False):
            errors.append("[X] Archive 2024 page is not marked as favorite")
        else:
            checks_passed.append("[C] Archive 2024 marked as favorite")

        # Check for 3 subsection pages
        archive_id = archive_page.get("_id")

        required_subsections = ["Old Marketing", "Legacy Documentation", "Past Projects"]
        found_subsections = []

        for required in required_subsections:
            subsection = _find_child_by_title(final_state_backend, archive_page, required)
            if subsection:
                found_subsections.append(subsection["title"])

        if len(found_subsections) < 3:
            errors.append(f"[X] Expected 3 subsections (Old Marketing, Legacy Documentation, Past Projects), found {len(found_subsections)}: {found_subsections}")
        else:
            checks_passed.append(f"[C] Found all 3 required subsections: {found_subsections}")

        # Check for explanatory callout at top of Archive 2024 page
        archive_blocks = _get_blocks_for_page(final_state_backend, archive_id)
        has_callout = any(block.get("type") == "callout" for block in archive_blocks)
        if not has_callout:
            errors.append("[X] Archive 2024 page missing explanatory callout")
        else:
            checks_passed.append("[C] Archive 2024 has explanatory callout")

        # Check if archived pages have been moved to subsections
        # Check if subsections have children (archived content redistributed)
        redistributed_count = 0
        for subsection_title in required_subsections:
            subsection = _find_child_by_title(final_state_backend, archive_page, subsection_title)
            if subsection:
                subsection_children = _get_child_pages(final_state_backend, subsection.get("_id"))
                redistributed_count += len(subsection_children)

        if redistributed_count == 0:
            errors.append("[X] No archived pages found redistributed to subsections")
        else:
            checks_passed.append("[C] archived pages found redistributed to subsections")

        checks_passed.append(f"[C] Found {redistributed_count} pages redistributed to subsections")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_project_reorganization(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate project documentation reorganization task."""
    errors: list[str] = []
    checks_passed: list[str] = []

    
    # Check for Archive - Q4 2024 page
    try:
        archive_page = _find_page_by_title(final_state_backend, "Archive - Q4 2024")
        if not archive_page:
            errors.append("[X] Archive - Q4 2024 page not found")
        else:
            checks_passed.append("[C] Archive - Q4 2024 page found")
    
        # Check for folder icon
        icon = archive_page.get("icon", "")
        if "folder" not in icon.lower() and "📁" not in icon and "📂" not in icon:
            errors.append("[X] Archive - Q4 2024 page does not have a folder icon")
        else:
            checks_passed.append("[C] Archive - Q4 2024 page has a folder icon")
    
        # Check if archive page is marked as favorite
        if not archive_page.get("isFavorite", False):
            errors.append("[X] Archive - Q4 2024 page is not marked as favorite")
        else:
            checks_passed.append("[C] Archive - Q4 2024 page is marked as favorite")
    
        # Get all child pages of the archive
        archive_id = archive_page.get("_id")
        child_pages = _get_child_pages(final_state_backend, archive_id)
    
        # Check if at least 3 of them have 'Project' in their title
        project_children = [p for p in child_pages if "project" in p.get("title", "").lower()]
        if len(project_children) < 3:
            errors.append(f"[X] Archive should have at least 3 project pages as children, found {len(project_children)}")
        else:
            checks_passed.append(f"[C] Archive should have at least 3 project pages as children, found {len(project_children)}")
    
        # Get blocks for the archive page to check for callout
        archive_blocks = _get_blocks_for_page(final_state_backend, archive_id)
    
        # Check for callout block
        callout_blocks = [b for b in archive_blocks if b.get("type") == "callout"]
        if not callout_blocks:
            errors.append("[X] Archive page does not contain a callout block summarizing moved items")
        else:
            checks_passed.append("[C] Archive page does contains a callout block summarizing moved items")
    
        # Check if any callout mentions the moved pages or contains a list
        callout_found = False
        for callout in callout_blocks:
            content = callout.get("content", "").lower()
            # Check if callout mentions moved items, archive, or contains keywords
            if any(word in content for word in ["moved", "archive", "reorganized", "contains", "includes", "following"]):
                callout_found = True
                break
    
        if not callout_found:
            errors.append("[X] Archive page callout block does not contain summary of moved items")
        else:
            checks_passed.append("[C] Archive page callout block does contains summary of moved items")
    
        # All checks passed
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_template_library_creation(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate creation of Template Library with template reorganization."""
    errors: list[str] = []

    checks_passed = []

    # Check for Template Library page
    try:
        library = _find_page_by_title(final_state_backend, "Template Library")
        if not library:
            errors.append("[X] Template Library page not found")
        else:
            checks_passed.append("[C] Template Library page found")

        # Check for books icon (can be 📚, 📖, book emoji, or 'books' text)
        icon = library.get("icon", "")
        if "book" not in icon.lower() and "📚" not in icon and "📖" not in icon:
            errors.append("[X] Template Library does not have a books icon")
        else:
            checks_passed.append("[C] Template Library created with books icon")

        # Check that all pages with 'Template' in title are moved under it
        library_id = library.get("_id")
        # Query pages with "template" in title
        template_pages_result = final_state_backend.query({
            "collection": "pages",
            "filter": {
                "title": {"$regex": "template", "$options": "i"}
            }
        })
        template_pages = [p for p in (template_pages_result if isinstance(template_pages_result, list) else []) if p.get("_id") != library_id]
    
        if not template_pages:
            errors.append("[X] No template pages found to organize")
        else:
            checks_passed.append("[C] template pages found to organize")

        # Check all template pages have library as parent
        templates_not_under_library = []
        for template in template_pages:
            if template.get("parentId") != library_id:
                templates_not_under_library.append(template.get("title", ""))
    
        if templates_not_under_library:
            errors.append(f"[X] Template pages not under library: {', '.join(templates_not_under_library)}")
        else:
            checks_passed.append(f"[C] All {len(template_pages)} template pages moved under library")

        # Check library content (heading, description, callout)
        library_blocks = _get_blocks_for_page(final_state_backend, library_id)
        if not library_blocks:
            errors.append("[X] Template Library has no content blocks")
        else:
            checks_passed.append("[C] Template Library has content blocks")

        # Check for required block types
        block_types = [block.get("type", "") for block in library_blocks]
    
        # Check for heading (heading1 or heading_1)
        has_heading = any(t in ["heading1", "heading_1", "h1"] for t in block_types)
        if not has_heading:
            errors.append("[X] Template Library missing heading block")
        else:
            checks_passed.append("[C] Template Library has heading block")
    
        # Check for paragraph
        has_paragraph = "paragraph" in block_types
        if not has_paragraph:
            errors.append("[X] Template Library missing description paragraph")
        else:
            checks_passed.append("[C] Template Library has description paragraph")
    
        # Check for callout
        has_callout = "callout" in block_types
        if not has_callout:
            errors.append("[X] Template Library missing callout block explaining how to use templates")
        else:
            checks_passed.append("[C] Template Library has callout block explaining how to use templates")
    
        checks_passed.append("[C] Library contains required blocks: heading, paragraph, and callout")

        # Check that empty template pages are archived
        empty_templates = []
        for template in template_pages:
            template_id = template.get("_id")
            template_blocks = _get_blocks_for_page(final_state_backend, template_id)
            if len(template_blocks) == 0:
                # This is an empty template
                if not template.get("isArchived", False):
                    empty_templates.append(template.get("title", ""))
    
        if empty_templates:
            errors.append(f"[X] Empty template pages not archived: {', '.join(empty_templates)}")
        else:
            checks_passed.append(f"[C] Empty template pages archived: {', '.join(empty_templates)}")
    
        # Count archived templates
        archived_count = sum(1 for t in template_pages if t.get("isArchived", False))
        if archived_count > 0:
            checks_passed.append(f"[C] {archived_count} empty template pages archived")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_comprehensive_documentation_structure(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate creation of comprehensive documentation structure under Engineering Wiki."""
    errors: list[str] = []

    checks_passed = []

    # Find the Engineering Wiki page
    try:
        wiki_page = _find_page_by_title(final_state_backend, "Engineering Wiki")
        if not wiki_page:
            errors.append("[X] Engineering Wiki page not found")
        else:
            checks_passed.append("[C] Engineering Wiki page found")
        wiki_id = wiki_page.get("_id")

        # Check for the 3 required subpages under Engineering Wiki
        required_subpages = ["API Reference", "Code Examples", "Troubleshooting Guide"]
        child_pages = _get_child_pages(final_state_backend, wiki_id)
    
        # Validate each required subpage exists
        found_subpages = []
        for required_title in required_subpages:
            found = False
            for child in child_pages:
                if child.get("title", "").strip() == required_title:
                    found = True
                    found_subpages.append(child)
                    break
            if not found:
                errors.append(f"[X] Required subpage '{required_title}' not found under Engineering Wiki")
            else:
                checks_passed.append(f"[C] Required subpage '{required_title}' found under Engineering Wiki")
    
        checks_passed.append("[C] All 3 required subpages created")

        # Validate structure of each new subpage
        for page in found_subpages:
            page_id = page.get("_id")
            page_title = page.get("title")
            blocks = _get_blocks_for_page(final_state_backend, page_id)
        
            if len(blocks) < 4:
                errors.append(f"[X] Page '{page_title}' does not have required structure (found {len(blocks)} blocks, need at least 4)")
            else:
                checks_passed.append(f"[C] Page '{page_title}' has required structure (found {len(blocks)} blocks, need at least 4)")
        
            # Check for required block types in order: heading1, paragraph, divider, and additional heading
            block_types = [block.get("type", "") for block in sorted(blocks, key=lambda b: b.get("order", 0))]
        
            # Check for heading1 (title heading)
            if not any(t in ["heading1", "heading_1"] for t in block_types):
                errors.append(f"[X] Page '{page_title}' missing title heading (heading1)")
            else:
                checks_passed.append(f"[C] Page '{page_title}' has title heading (heading1)")
        
            # Check for paragraph (overview)
            if "paragraph" not in block_types:
                errors.append(f"[X] Page '{page_title}' missing overview paragraph")
            else:
                checks_passed.append(f"[C] Page '{page_title}' has overview paragraph")
        
            # Check for divider
            if "divider" not in block_types:
                errors.append(f"[X] Page '{page_title}' missing divider")
            else:
                checks_passed.append(f"[C] Page '{page_title}' has divider")
        
            # Check for additional heading blocks (heading2, heading3, etc.)
            heading_types = ["heading2", "heading_2", "heading3", "heading_3", "heading"]
            has_section_heading = any(t in heading_types for t in block_types)
            if not has_section_heading:
                errors.append(f"[X] Page '{page_title}' missing section headings")
            else:
                checks_passed.append(f"[C] Page '{page_title}' has section headings")
        
        checks_passed.append("[C] All subpages have required structure (heading, paragraph, divider, section headings)")

        # Check that parent wiki page has been updated with table of contents
        wiki_blocks = _get_blocks_for_page(final_state_backend, wiki_id)
    
        # Look for bulletedList blocks that could be a table of contents
        bulleted_lists = [b for b in wiki_blocks if b.get("type") == "bulletedList"]
    
        if not bulleted_lists:
            errors.append("[X] Engineering Wiki page missing table of contents (no bulletedList blocks found)")
        else:
            checks_passed.append("[C] Engineering Wiki page has table of contents (bulletedList blocks found)")
    
        # Check if any bulletedList mentions the new pages
        toc_found = False
        for block in bulleted_lists:
            content = block.get("content", "").lower()
            if any(title.lower() in content for title in required_subpages):
                toc_found = True
                break
    
        if not toc_found:
            errors.append("[X] Engineering Wiki page table of contents does not link to new subpages")
        else:
            checks_passed.append("[C] Engineering Wiki page table of contents link to new subpages")
    
        checks_passed.append("[C] Parent wiki page updated with table of contents")

        # Verify total child count
        total_children = len(child_pages)
        if total_children < 4:
            errors.append(f"[X] Engineering Wiki should have at least 4 child pages total, found {total_children}")
        else:
            checks_passed.append(f"[C] Engineering Wiki should have at least 4 child pages total, found {total_children}")
    
        checks_passed.append(f"[C] Engineering Wiki has {total_children} child pages (≥4 required)")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_learning_and_development_hub(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate learning and development hub creation with proper structure."""
    errors: list[str] = []

    checks_passed = []

    # Check for Learning Hub page
    try:
        learning_hub = _find_page_by_title(final_state_backend, "Learning Hub")
        if not learning_hub:
            errors.append("[X] Learning Hub page not found")
        else:
            checks_passed.append("[C] Learning Hub page found")

        # Check for graduation cap icon
        icon = learning_hub.get("icon", "")
        if "🎓" not in icon and "graduation" not in icon.lower() and "cap" not in icon.lower():
            errors.append("[X] Learning Hub does not have a graduation cap icon")
        else:
            checks_passed.append("[C] Learning Hub created with graduation cap icon")

        # Check for 3 required subpages
        learning_hub_id = learning_hub.get("_id")
        child_pages = _get_child_pages(final_state_backend, learning_hub_id)
    
        # Find specific subpages
        training_materials = None
        skills_assessment = None
        career_development = None
    
        for child in child_pages:
            title = child.get("title", "").lower()
            if "training materials" in title:
                training_materials = child
            elif "skills assessment" in title:
                skills_assessment = child
            elif "career development" in title:
                career_development = child
    
        if not training_materials:
            errors.append("[X] Training Materials subpage not found under Learning Hub")
        else:
            checks_passed.append("[C] Training Materials subpage found under Learning Hub")
        if not skills_assessment:
            errors.append("[X] Skills Assessment subpage not found under Learning Hub")
        else:
            checks_passed.append("[C] Skills Assessment subpage found under Learning Hub")
        if not career_development:
            errors.append("[X] Career Development subpage not found under Learning Hub")
        else:
            checks_passed.append("[C] All 3 required subpages created")

        # Check main hub content
        hub_blocks = _get_blocks_for_page(final_state_backend, learning_hub_id)
    
        # Check for required block types
        has_heading1 = False
        has_paragraph = False
        has_numbered_list = False
    
        for block in hub_blocks:
            block_type = block.get("type", "")
            if block_type == "heading1":
                has_heading1 = True
            elif block_type == "paragraph":
                has_paragraph = True
            elif block_type == "numberedList":
                has_numbered_list = True
    
        if not has_heading1:
            errors.append("[X] Learning Hub missing heading1 block")
        else:
            checks_passed.append("[C] Learning Hub has heading1 block")
        if not has_paragraph:
            errors.append("[X] Learning Hub missing paragraph block")
        else:
            checks_passed.append("[C] Learning Hub has paragraph block")
        if not has_numbered_list:
            errors.append("[X] Learning Hub missing numberedList block")
        else:
            checks_passed.append("[C] Main hub contains required content types")

        # Check that Weekly Standup Template is under Training Materials
        weekly_standup = _find_page_by_title(final_state_backend, "Weekly Standup Template")
        if not weekly_standup:
            errors.append("[X] Weekly Standup Template page not found")
        else:
            checks_passed.append("[C] Weekly Standup Template page found")
    
        training_materials_id = training_materials.get("_id")
        if weekly_standup.get("parentId") != training_materials_id:
            errors.append("[X] Weekly Standup Template not moved under Training Materials")
        else:
            checks_passed.append("[C] Weekly Standup Template moved under Training Materials")

        # Verify proper 3-level hierarchy
        # Level 1: Learning Hub (no parent)
        # Level 2: Training Materials, Skills Assessment, Career Development
        # Level 3: Weekly Standup Template under Training Materials
        if learning_hub.get("parentId"):
            errors.append("[X] Learning Hub should be a top-level page but has a parent")
        else:
            checks_passed.append("[C] Learning Hub should be a top-level page but has a parent")
    
        hierarchy_check = _check_page_is_child_of(learning_hub, training_materials) and \
                         _check_page_is_child_of(learning_hub, skills_assessment) and \
                         _check_page_is_child_of(learning_hub, career_development) and \
                         _check_page_is_child_of(training_materials, weekly_standup)
    
        if not hierarchy_check:
            errors.append("[X] Proper 3-level hierarchy not established")
        else:
            checks_passed.append("[C] Proper 3-level hierarchy established")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_team_onboarding_hub(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate creation of comprehensive team onboarding hub."""
    errors: list[str] = []
    checks_passed: list[str] = []

    
    # Check for Team Onboarding page
    try:
        onboarding_page = _find_page_by_title(final_state_backend, "Team Onboarding")
        if not onboarding_page:
            errors.append("[X] Team Onboarding page not found")
        else:
            checks_passed.append("[C] Team Onboarding page found")
    
        # Check for people icon
        icon = onboarding_page.get("icon", "")
        if "people" not in icon.lower() and "👥" not in icon and "👫" not in icon and "👬" not in icon and "👭" not in icon and "🧑‍🤝‍🧑" not in icon:
            errors.append("[X] Team Onboarding page does not have a people icon")
        else:
            checks_passed.append("[C] Team Onboarding page has a people icon")
    
        # Check if marked as favorite
        if not onboarding_page.get("isFavorite", False):
            errors.append("[X] Team Onboarding page is not marked as favorite")
        else:
            checks_passed.append("[C] Team Onboarding page is marked as favorite")
    
        # Check if it's a child of Getting Started page
        getting_started = _find_page_by_title(final_state_backend, "Getting Started")
        if not getting_started:
            errors.append("[X] Getting Started page not found")
        else:
            checks_passed.append("[C] Getting Started page found")
    
        if onboarding_page.get("parentId") != getting_started.get("_id"):
            errors.append("[X] Team Onboarding page is not a child of Getting Started page")
        else:
            checks_passed.append("[C] Team Onboarding page is a child of Getting Started page")
    
        # Check for 4 specific subpages
        onboarding_id = onboarding_page.get("_id")
        child_pages = _get_child_pages(final_state_backend, onboarding_id)
    
        required_subpages = [
            "Getting Started Guide",
            "Development Setup",
            "Team Resources",
            "First Week Tasks"
        ]
    
        found_subpages = []
        for req_title in required_subpages:
            found = False
            for child in child_pages:
                if child.get("title", "").lower() == req_title.lower():
                    found = True
                    found_subpages.append(req_title)
                    break
            if not found:
                errors.append(f"[X] Required subpage '{req_title}' not found under Team Onboarding")
            else:
                checks_passed.append(f"[C] Required subpage '{req_title}' found under Team Onboarding")
    
        # Check content of main hub
        hub_blocks = _get_blocks_for_page(final_state_backend, onboarding_id)
    
        # Check for heading1
        has_heading = any(b.get("type") in ["heading1", "heading_1"] for b in hub_blocks)
        if not has_heading:
            errors.append("[X] Team Onboarding page missing heading1 block")
        else:
            checks_passed.append("[C] Team Onboarding page has heading1 block")
    
        # Check for paragraph (welcome paragraph)
        has_paragraph = any(b.get("type") == "paragraph" for b in hub_blocks)
        if not has_paragraph:
            errors.append("[X] Team Onboarding page missing welcome paragraph")
        else:
            checks_passed.append("[C] Team Onboarding page has welcome paragraph")
    
        # Check for bulletedList
        has_bulleted_list = any(b.get("type") in ["bulletedList", "bulleted_list", "bulletedListItem", "bulleted_list_item"] for b in hub_blocks)
        if not has_bulleted_list:
            errors.append("[X] Team Onboarding page missing bulleted list")
        else:
            checks_passed.append("[C] Team Onboarding page has bulleted list")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_meeting_notes_reorganization(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate meeting notes template creation and organization."""
    errors: list[str] = []

    checks_passed = []

    # Check that pages with 'Meeting' in title can be found
    try:
        meeting_pages = _find_pages_by_title(final_state_backend, "Meeting")
        if len(meeting_pages) < 1:
            errors.append("[X] No pages with 'Meeting' in the title found")
        else:
            checks_passed.append(f"[C] Found {len(meeting_pages)} pages with 'Meeting' in title")

        # Check for new 'Meeting Notes Template - 2025' page
        template_2025 = _find_page_by_title(final_state_backend, "Meeting Notes Template - 2025")
        if not template_2025:
            errors.append("[X] Meeting Notes Template - 2025 page not found")
        else:
            checks_passed.append("[C] Meeting Notes Template - 2025 created")

        # Check that template is marked as favorite
        if not template_2025.get("isFavorite", False):
            errors.append("[X] Meeting Notes Template - 2025 is not marked as favorite")
        else:
            checks_passed.append("[C] Template marked as favorite")

        # Check that template is a child of main 'Meeting Notes' page
        main_meeting_notes = _find_page_by_title(final_state_backend, "^Meeting Notes$")
        if not main_meeting_notes:
            errors.append("[X] Main 'Meeting Notes' page not found")
        else:
            checks_passed.append("[C] Main 'Meeting Notes' page found")
    
        if template_2025.get("parentId") != main_meeting_notes.get("_id"):
            errors.append("[X] Meeting Notes Template - 2025 is not a child of main Meeting Notes page")
        else:
            checks_passed.append("[C] Template is child of main Meeting Notes page")

        # Check template content structure
        template_blocks = _get_blocks_for_page(final_state_backend, template_2025.get("_id"))
        if len(template_blocks) < 4:
            errors.append(f"[X] Template should have at least 4 blocks for required structure, found {len(template_blocks)}")
        else:
            checks_passed.append(f"[C] Template should have at least 4 blocks for required structure, found {len(template_blocks)}")

        # Check for required block types
        block_types = [block.get("type", "") for block in template_blocks]
    
        # Check for heading1 (date heading)
        has_heading1 = any(t in ["heading1", "heading_1"] for t in block_types)
        if not has_heading1:
            errors.append("[X] Template missing heading1 block for date heading")
        else:
            checks_passed.append("[C] Template has heading1 block for date heading")
    
        # Check for bulletedList (attendees checklist)
        has_bulleted = any(t in ["bulletedList", "bulleted_list"] for t in block_types)
        if not has_bulleted:
            errors.append("[X] Template missing bulletedList block for attendees")
        else:
            checks_passed.append("[C] Template has bulletedList block for attendees")
    
        # Check for numberedList (agenda)
        has_numbered = any(t in ["numberedList", "numbered_list"] for t in block_types)
        if not has_numbered:
            errors.append("[X] Template missing numberedList block for agenda")
        else:
            checks_passed.append("[C] Template has numberedList block for agenda")
    
        # Check for todo (action items)
        has_todo = "todo" in block_types
        if not has_todo:
            errors.append("[X] Template missing todo blocks for action items")
        else:
            checks_passed.append("[C] Template has todo blocks for action items")
    
        checks_passed.append("[C] Template contains required blocks: heading1, bulletedList, numberedList, and todo")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_project_planning_workspace(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate project planning workspace creation with hub and subpages."""
    errors: list[str] = []

    checks_passed = []

    # Check for Product Planning Hub page
    try:
        hub = _find_page_by_title(final_state_backend, "Product Planning Hub")
        if not hub:
            errors.append("[X] Product Planning Hub page not found")
        else:
            checks_passed.append("[C] Product Planning Hub page found")

        # Check for target icon
        icon = hub.get("icon", "")
        if "target" not in icon.lower() and "🎯" not in icon:
            errors.append("[X] Product Planning Hub does not have a target icon")
        else:
            checks_passed.append("[C] Product Planning Hub created with target icon")

        # Get hub ID for checking children
        hub_id = hub.get("_id")
        child_pages = _get_child_pages(final_state_backend, hub_id)

        # Check for required subpages
        required_subpages = ["Requirements Gathering", "Technical Specifications", "Implementation Timeline"]
        found_subpages = []
    
        for child in child_pages:
            title = child.get("title", "")
            if title in required_subpages:
                found_subpages.append(title)

        # Check all required subpages exist
        missing_subpages = set(required_subpages) - set(found_subpages)
        if missing_subpages:
            errors.append(f"[X] Missing required subpages: {', '.join(missing_subpages)}")
        else:
            checks_passed.append("[C] All 3 required subpages created")

        # Check that Product Specs page is also a child
        product_specs_found = False
        for child in child_pages:
            if child.get("title") == "Product Specs":
                product_specs_found = True
                break
    
        if not product_specs_found:
            errors.append("[X] Product Specs page not found under Product Planning Hub")
        else:
            checks_passed.append("[C] Product Specs page moved under hub")

        # Verify total child count is exactly 4
        if len(child_pages) != 4:
            errors.append(f"[X] Expected 4 child pages under hub, found {len(child_pages)}")
        else:
            checks_passed.append("[C] Hub has exactly 4 child pages")

        # Validate content for each required subpage
        for subpage_title in required_subpages:
            subpage = _find_page_by_title(child_pages, subpage_title)
            if not subpage:
                errors.append(f"[X] Could not find subpage {subpage_title} in children")
            else:
                checks_passed.append(f"[C] Could find subpage {subpage_title} in children")
        
            page_id = subpage.get("_id")
            page_blocks = _get_blocks_for_page(final_state_backend, page_id)
        
            # Check for required block types
            block_types = [block.get("type") for block in page_blocks]
        
            # Check for heading1 (or heading_1)
            has_heading = "heading1" in block_types or "heading_1" in block_types
            if not has_heading:
                errors.append(f"[X] {subpage_title} missing heading1 block")
            else:
                checks_passed.append(f"[C] {subpage_title} has heading1 block")
        
            # Check for paragraph
            if "paragraph" not in block_types:
                errors.append(f"[X] {subpage_title} missing paragraph block")
            else:
                checks_passed.append(f"[C] {subpage_title} has paragraph block")
        
            # Check for todo
            if "todo" not in block_types:
                errors.append(f"[X] {subpage_title} missing todo block")
            else:
                checks_passed.append(f"[C] {subpage_title} has todo block")
    
        checks_passed.append("[C] All subpages contain required content blocks")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_archive_organization_v2(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate archive management organization task."""
    errors: list[str] = []
    checks_passed: list[str] = []

    
    # Check for Archive Management page
    try:
        archive_mgmt = _find_page_by_title(final_state_backend, "Archive Management")
        if not archive_mgmt:
            errors.append("[X] Archive Management page not found")
        else:
            checks_passed.append("[C] Archive Management page found")
    
        # Check for warning icon
        icon = archive_mgmt.get("icon", "")
        if "warning" not in icon.lower() and "⚠" not in icon and "⚡" not in icon and "🚨" not in icon:
            errors.append("[X] Archive Management page does not have a warning icon")
        else:
            checks_passed.append("[C] Archive Management page has a warning icon")
    
        # Check if marked as favorite
        if not archive_mgmt.get("isFavorite", False):
            errors.append("[X] Archive Management page is not marked as favorite")
        else:
            checks_passed.append("[C] Archive Management page is marked as favorite")
    
        # Get blocks for the Archive Management page
        mgmt_blocks = _get_blocks_for_page(final_state_backend, archive_mgmt.get("_id"))
    
        # Count different block types
        heading_blocks = [b for b in mgmt_blocks if b.get("type", "").startswith("heading")]
        paragraph_blocks = [b for b in mgmt_blocks if b.get("type") == "paragraph"]
        todo_blocks = [b for b in mgmt_blocks if b.get("type") == "todo"]
    
        # Check for multiple heading blocks (for archive categories)
        if len(heading_blocks) < 2:
            errors.append(f"[X] Expected multiple heading blocks for archive categories, found {len(heading_blocks)}")
        else:
            checks_passed.append(f"[C] Expected multiple heading blocks for archive categories, found {len(heading_blocks)}")
    
        # Check for paragraph blocks describing archival process
        if len(paragraph_blocks) < 1:
            errors.append("[X] No paragraph blocks found describing the archival process")
        else:
            checks_passed.append("[C] paragraph blocks found describing the archival process")
    
        # Check for todo blocks for quarterly cleanup tasks
        if len(todo_blocks) < 1:
            errors.append("[X] No todo blocks found for quarterly cleanup tasks")
        else:
            checks_passed.append("[C] todo blocks found for quarterly cleanup tasks")
    
        # Check that archived pages are moved under Archive Management
        archive_mgmt_id = archive_mgmt.get("_id")
        archived_pages_result = final_state_backend.query({
            "collection": "pages",
            "filter": {"isArchived": True}
        })
        archived_pages = [p for p in (archived_pages_result if isinstance(archived_pages_result, list) else []) if p.get("_id") != archive_mgmt_id]
    
        # Count how many archived pages have Archive Management as parent
        archived_under_mgmt = [p for p in archived_pages if p.get("parentId") == archive_mgmt_id]
    
        # We expect all previously parentless archived pages to be under management
        # From exploration, all 6 archived pages had no parent initially
        if len(archived_under_mgmt) < 1:
            errors.append("[X] No archived pages found under Archive Management page")
        else:
            checks_passed.append("[C] archived pages found under Archive Management page")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_roadmap_duplication_and_customization(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Project Roadmap duplication, customization, and relocation."""
    errors: list[str] = []
    checks_passed: list[str] = []

    
    # Check that original Project Roadmap still exists
    try:
        original_roadmap = _find_page_by_title(final_state_backend, "Project Roadmap")
        if not original_roadmap:
            errors.append("[X] Original Project Roadmap page not found")
        else:
            checks_passed.append("[C] Original Project Roadmap page found")
    
        # Check for new duplicated page with correct title
        new_roadmap = _find_page_by_title(final_state_backend, "Project Roadmap - 2025 Edition")
        if not new_roadmap:
            errors.append("[X] Project Roadmap - 2025 Edition page not found")
        else:
            checks_passed.append("[C] Project Roadmap - 2025 Edition page found")
    
        # Check for rocket icon
        icon = new_roadmap.get("icon", "")
        if "rocket" not in icon.lower() and "🚀" not in icon:
            errors.append("[X] Project Roadmap - 2025 Edition does not have a rocket icon")
        else:
            checks_passed.append("[C] Project Roadmap - 2025 Edition has a rocket icon")
    
        # Find Project Documentation page
        project_docs = _find_page_by_title(final_state_backend, "Project Documentation")
        if not project_docs:
            errors.append("[X] Project Documentation page not found")
        else:
            checks_passed.append("[C] Project Documentation page found")
    
        # Check that new roadmap is under Project Documentation
        if new_roadmap.get("parentId") != project_docs.get("_id"):
            errors.append("[X] Project Roadmap - 2025 Edition is not under Project Documentation")
        else:
            checks_passed.append("[C] Project Roadmap - 2025 Edition is under Project Documentation")
    
        # Check that new roadmap is marked as favorite
        if not new_roadmap.get("isFavorite", False):
            errors.append("[X] Project Roadmap - 2025 Edition is not marked as favorite")
        else:
            checks_passed.append("[C] Project Roadmap - 2025 Edition is marked as favorite")
    
        # Check for required content blocks
        roadmap_blocks = _get_blocks_for_page(final_state_backend, new_roadmap.get("_id"))
        if not roadmap_blocks:
            errors.append("[X] Project Roadmap - 2025 Edition has no content blocks")
        else:
            checks_passed.append("[C] Project Roadmap - 2025 Edition has content blocks")
    
        # Check for required block types
        block_types = [block.get("type") for block in roadmap_blocks]
    
        # Check for heading1 (vision heading)
        if "heading1" not in block_types:
            errors.append("[X] Project Roadmap - 2025 Edition missing heading1 block for vision")
        else:
            checks_passed.append("[C] Project Roadmap - 2025 Edition has heading1 block for vision")
    
        # Check for numberedList (quarterly goals)
        if "numberedList" not in block_types:
            errors.append("[X] Project Roadmap - 2025 Edition missing numberedList block for quarterly goals")
        else:
            checks_passed.append("[C] Project Roadmap - 2025 Edition has numberedList block for quarterly goals")
    
        # Check for bulletedList (key milestones)
        if "bulletedList" not in block_types:
            errors.append("[X] Project Roadmap - 2025 Edition missing bulletedList block for key milestones")
        else:
            checks_passed.append("[C] Project Roadmap - 2025 Edition has bulletedList block for key milestones")
    
        # Check for quote block (team motto)
        if "quote" not in block_types:
            errors.append("[X] Project Roadmap - 2025 Edition missing quote block for team motto")
        else:
            checks_passed.append("[C] Project Roadmap - 2025 Edition has quote block for team motto")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_onboarding_hub_creation(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate comprehensive onboarding hub creation with duplicated template."""
    errors: list[str] = []
    checks_passed: list[str] = []

    
    # Check for Team Onboarding Hub page
    try:
        hub_page = _find_page_by_title(final_state_backend, "Team Onboarding Hub")
        if not hub_page:
            errors.append("[X] Team Onboarding Hub page not found")
        else:
            checks_passed.append("[C] Team Onboarding Hub page found")
    
        # Check hub has welcome icon
        hub_icon = hub_page.get("icon", "")
        if "welcome" not in hub_icon.lower() and "👋" not in hub_icon and "🙏" not in hub_icon and "🤗" not in hub_icon:
            errors.append("[X] Team Onboarding Hub does not have a welcome icon")
        else:
            checks_passed.append("[C] Team Onboarding Hub has a welcome icon")
    
        # Check for New Hire First Week Guide page (duplicated from template)
        guide_page = _find_page_by_title(final_state_backend, "New Hire First Week Guide")
        if not guide_page:
            errors.append("[X] New Hire First Week Guide page not found")
        else:
            checks_passed.append("[C] New Hire First Week Guide page found")
    
        # Check guide has star icon
        guide_icon = guide_page.get("icon", "")
        if "star" not in guide_icon.lower() and "⭐" not in guide_icon and "🌟" not in guide_icon:
            errors.append("[X] New Hire First Week Guide does not have a star icon")
        else:
            checks_passed.append("[C] New Hire First Week Guide has a star icon")
    
        # Check guide content structure
        guide_blocks = _get_blocks_for_page(final_state_backend, guide_page.get("_id"))
        if not guide_blocks:
            errors.append("[X] New Hire First Week Guide has no content blocks")
        else:
            checks_passed.append("[C] New Hire First Week Guide has content blocks")
    
        # Count block types
        heading_count = 0
        todo_count = 0
        callout_count = 0
    
        for block in guide_blocks:
            block_type = block.get("type", "")
            if block_type in ["heading1", "heading2", "heading3", "heading_1", "heading_2", "heading_3"]:
                heading_count += 1
            elif block_type == "todo":
                todo_count += 1
            elif block_type == "callout":
                callout_count += 1
    
        # Validate content requirements
        if heading_count < 2:
            errors.append(f"[X] New Hire First Week Guide needs at least 2 headings, found {heading_count}")
        else:
            checks_passed.append(f"[C] New Hire First Week Guide needs at least 2 headings, found {heading_count}")
    
        if todo_count < 2:
            errors.append(f"[X] New Hire First Week Guide needs multiple todo items, found {todo_count}")
        else:
            checks_passed.append(f"[C] New Hire First Week Guide needs multiple todo items, found {todo_count}")
    
        if callout_count < 1:
            errors.append("[X] New Hire First Week Guide needs at least 1 callout block with important company resources")
        else:
            checks_passed.append("[C] New Hire First Week Guide needs at least 1 callout block with important company resources")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_architecture_consolidation(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate architecture documentation consolidation and reorganization."""
    errors: list[str] = []

    checks_passed = []

    # Check for System Architecture Hub page
    try:
        hub = _find_page_by_title(final_state_backend, "System Architecture Hub")
        if not hub:
            errors.append("[X] System Architecture Hub page not found")
        else:
            checks_passed.append("[C] System Architecture Hub page found")

        # Check for building icon
        icon = hub.get("icon", "")
        if "🏢" not in icon and "🏗️" not in icon and "building" not in icon.lower() and "🏛️" not in icon:
            errors.append("[X] System Architecture Hub does not have a building icon")
        else:
            checks_passed.append("[C] System Architecture Hub created with building icon")

        # Check if hub is marked as favorite
        if not hub.get("isFavorite", False):
            errors.append("[X] System Architecture Hub is not marked as favorite")
        else:
            checks_passed.append("[C] System Architecture Hub marked as favorite")

        # Check that Architecture page was moved under the hub
        architecture_page = _find_page_by_title(final_state_backend, "Architecture")
        if not architecture_page:
            errors.append("[X] Architecture page not found")
        else:
            checks_passed.append("[C] Architecture page found")
    
        if architecture_page.get("parentId") != hub.get("_id"):
            errors.append("[X] Architecture page is not under System Architecture Hub")
        else:
            checks_passed.append("[C] Architecture page moved under System Architecture Hub")

        # Check that Frontend Architecture and Backend Architecture are still under Architecture
        frontend_arch = _find_page_by_title(final_state_backend, "Frontend Architecture")
        backend_arch = _find_page_by_title(final_state_backend, "Backend Architecture")
    
        if not frontend_arch or not backend_arch:
            errors.append("[X] Frontend Architecture or Backend Architecture pages not found")
        else:
            checks_passed.append("[C] Frontend Architecture or Backend Architecture pages found")
    
        if frontend_arch.get("parentId") != architecture_page.get("_id"):
            errors.append("[X] Frontend Architecture is not under Architecture page")
        else:
            checks_passed.append("[C] Frontend Architecture is under Architecture page")
        if backend_arch.get("parentId") != architecture_page.get("_id"):
            errors.append("[X] Backend Architecture is not under Architecture page")
        else:
            checks_passed.append("[C] Frontend and Backend Architecture pages preserved under Architecture")

        # Check that Component Library and State Management are still under Frontend Architecture
        component_lib = _find_page_by_title(final_state_backend, "Component Library")
        state_mgmt = _find_page_by_title(final_state_backend, "State Management")
    
        if component_lib and component_lib.get("parentId") != frontend_arch.get("_id"):
            errors.append("[X] Component Library is not under Frontend Architecture")
        else:
            checks_passed.append("[C] Component Library is under Frontend Architecture")
        if state_mgmt and state_mgmt.get("parentId") != frontend_arch.get("_id"):
            errors.append("[X] State Management is not under Frontend Architecture")
        else:
            checks_passed.append("[C] Component Library and State Management preserved under Frontend Architecture")

        # Check that API Design Patterns is still under Backend Architecture
        api_patterns = _find_page_by_title(final_state_backend, "API Design Patterns")
        if api_patterns and api_patterns.get("parentId") != backend_arch.get("_id"):
            errors.append("[X] API Design Patterns is not under Backend Architecture")
        else:
            checks_passed.append("[C] API Design Patterns preserved under Backend Architecture")

        # Check for overview content in the hub
        hub_blocks = _get_blocks_for_page(final_state_backend, hub.get("_id"))
        if len(hub_blocks) < 3:
            errors.append(f"[X] System Architecture Hub has insufficient content blocks ({len(hub_blocks)} found, need at least 3)")
        else:
            checks_passed.append(f"[C] System Architecture Hub has insufficient content blocks ({len(hub_blocks)} found, need at least 3)")
    
        # Check for heading blocks
        heading_blocks = [b for b in hub_blocks if b.get("type") in ["heading1", "heading2", "heading3", "heading_1", "heading_2", "heading_3"]]
        if not heading_blocks:
            errors.append("[X] System Architecture Hub does not contain any heading blocks")
        else:
            checks_passed.append("[C] System Architecture Hub does contains any heading blocks")
    
        # Check for bullet list blocks
        bullet_blocks = [b for b in hub_blocks if b.get("type") in ["bullet", "bulleted_list", "bullet_list", "list"]]
        if not bullet_blocks:
            errors.append("[X] System Architecture Hub does not contain any bullet list blocks")
        else:
            checks_passed.append("[C] System Architecture Hub does contains any bullet list blocks")
    
        checks_passed.append(f"[C] System Architecture Hub contains {len(heading_blocks)} heading(s) and {len(bullet_blocks)} bullet list(s)")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_design_system_hub_creation(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Design System Hub creation with child pages and content."""
    errors: list[str] = []
    checks_passed: list[str] = []

    
    # Check for Design System Hub page
    try:
        hub = _find_page_by_title(final_state_backend, "Design System Hub")
        if not hub:
            errors.append("[X] Design System Hub page not found")
        else:
            checks_passed.append("[C] Design System Hub page found")
    
        # Check for palette icon
        icon = hub.get("icon", "")
        if "palette" not in icon.lower() and "🎨" not in icon and "🖌️" not in icon and "🎭" not in icon:
            errors.append("[X] Design System Hub does not have a palette icon")
        else:
            checks_passed.append("[C] Design System Hub has a palette icon")
    
        hub_id = hub.get("_id")
    
        # Check for exactly 3 child pages
        child_pages = _get_child_pages(final_state_backend, hub_id)
        child_titles = [page.get("title", "") for page in child_pages]
        required_children = ["Design Principles", "Component Guidelines", "Design Tokens"]
    
        for required_title in required_children:
            if not any(title == required_title for title in child_titles):
                errors.append(f"[X] Missing required child page: {required_title}")
            else:
                checks_passed.append(f"[C] has required child page: {required_title}")
    
        # Check for callout block in main hub
        hub_blocks = _get_blocks_for_page(final_state_backend, hub_id)
        has_callout = any(block.get("type") == "callout" for block in hub_blocks)
        if not has_callout:
            errors.append("[X] Design System Hub does not have a callout block")
        else:
            checks_passed.append("[C] Design System Hub has a callout block")
    
        # Check Design Principles page content
        principles_page = _find_page_by_title_pattern_and_parent(final_state_backend, "Design Principles", hub.get("_id"))
        if not principles_page:
            errors.append("[X] Design Principles page not found")
        else:
            checks_passed.append("[C] Design Principles page found")
    
        principles_blocks = _get_blocks_for_page(final_state_backend, principles_page.get("_id"))
        principles_headings = [block.get("content", "") for block in principles_blocks 
                              if block.get("type") in ["heading1", "heading2", "heading3", "heading_1", "heading_2", "heading_3"]]
    
        required_headings = ["Consistency", "Accessibility", "User Experience"]
        for heading in required_headings:
            if not any(heading in h for h in principles_headings):
                errors.append(f"[X] Design Principles missing heading: {heading}")
            else:
                checks_passed.append(f"[C] Design Principles has heading: {heading}")
    
        # Check that each heading has following paragraph content
        for i, block in enumerate(principles_blocks):
            if block.get("type") in ["heading1", "heading2", "heading3", "heading_1", "heading_2", "heading_3"]:
                content = block.get("content", "")
                if any(heading in content for heading in required_headings):
                    # Check if next block is a paragraph
                    if i + 1 < len(principles_blocks):
                        next_block = principles_blocks[i + 1]
                        if next_block.get("type") != "paragraph":
                            errors.append(f"[X] Heading '{content}' not followed by paragraph block")
                        else:
                            checks_passed.append(f"[C] Heading '{content}' followed by paragraph block")
                    else:
                        errors.append(f"[X] Heading '{content}' has no following content")
    
        # Check Component Guidelines page content
        guidelines_page = _find_page_by_title_pattern_and_parent(final_state_backend, "Component Guidelines", hub.get("_id"))
        if not guidelines_page:
            errors.append("[X] Component Guidelines page not found")
        else:
            checks_passed.append("[C] Component Guidelines page found")
    
        guidelines_blocks = _get_blocks_for_page(final_state_backend, guidelines_page.get("_id"))
        guidelines_headings = [block.get("content", "") for block in guidelines_blocks 
                              if block.get("type") in ["heading1", "heading2", "heading3", "heading_1", "heading_2", "heading_3"]]
    
        required_component_headings = ["Button Components", "Form Elements", "Navigation"]
        for heading in required_component_headings:
            if not any(heading in h for h in guidelines_headings):
                errors.append(f"[X] Component Guidelines missing heading: {heading}")
            else:
                checks_passed.append(f"[C] Component Guidelines has heading: {heading}")
    
        # Check that each heading has following bulleted list
        has_bulleted_lists = 0
        for i, block in enumerate(guidelines_blocks):
            if block.get("type") in ["heading1", "heading2", "heading3", "heading_1", "heading_2", "heading_3"]:
                content = block.get("content", "")
                if any(heading in content for heading in required_component_headings):
                    # Check if there's a bulleted list after this heading
                    for j in range(i + 1, len(guidelines_blocks)):
                        if guidelines_blocks[j].get("type") in ["bulleted_list_item", "bulleted_list", "bullet"]:
                            has_bulleted_lists += 1
                            break
                        elif guidelines_blocks[j].get("type") in ["heading1", "heading2", "heading3", "heading_1", "heading_2", "heading_3"]:
                            # Next heading found before any list
                            break
    
        if has_bulleted_lists < 3:
            errors.append("[X] Component Guidelines does not have bulleted lists for all required headings")
        else:
            checks_passed.append("[C] Component Guidelines has bulleted lists for all required headings")
    
        # Check that at least 1 component-related page was moved under guidelines
        guidelines_id = guidelines_page.get("_id")
        guidelines_children = _get_child_pages(final_state_backend, guidelines_id)
    
        # Check if any child page has component-related content
        has_component_child = False
        for child in guidelines_children:
            child_title = child.get("title", "").lower()
            if "component" in child_title:
                has_component_child = True
                break
    
        if not has_component_child:
            errors.append("[X] No component-related page found under Component Guidelines page")
        else:
            checks_passed.append("[C] component-related page found under Component Guidelines page")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_engineering_documentation_restructure(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate engineering documentation restructuring task."""
    errors: list[str] = []
    checks_passed: list[str] = []

    
    # Check 1: Engineering Wiki page still exists
    try:
        eng_wiki = _find_page_by_title(final_state_backend, "Engineering Wiki")
        if not eng_wiki:
            errors.append("[X] Engineering Wiki page not found")
        else:
            checks_passed.append("[C] Engineering Wiki page found")
    
        # Check 2: Engineering Wiki content preserved (check key blocks still exist)
        eng_wiki_blocks = _get_blocks_for_page(final_state_backend, eng_wiki["_id"])
        has_tech_stack = any("Tech Stack" in block.get("content", "") for block in eng_wiki_blocks)
        has_dev_setup = any("Development Setup" in block.get("content", "") for block in eng_wiki_blocks)
        if not (has_tech_stack or has_dev_setup):
            errors.append("[X] Original Engineering Wiki content not preserved")
        else:
            checks_passed.append("[C] Original Engineering Wiki content preserved")
    
        # Check 3: Code Standards & Guidelines page exists as child of Engineering Wiki
        code_standards = _find_page_by_title_pattern_and_parent(final_state_backend, "Code Standards & Guidelines", eng_wiki.get("_id"))
        if not code_standards:
            errors.append("[X] Code Standards & Guidelines page not found as child of Engineering Wiki")
        else:
            checks_passed.append("[C] Code Standards & Guidelines page found as child of Engineering Wiki")
    
        # Check 4: Shield icon on Code Standards page
        icon = code_standards.get("icon", "")
        if "shield" not in icon.lower() and "🛡" not in icon and "🛡️" not in icon:
            errors.append("[X] Code Standards & Guidelines does not have a shield icon")
        else:
            checks_passed.append("[C] Code Standards & Guidelines has a shield icon")
    
        # Check 5: Content validation for Code Standards page
        standards_blocks = _get_blocks_for_page(final_state_backend, code_standards["_id"])
    
        # Check for Coding Standards heading
        has_coding_standards_heading = any(
            block.get("type", "").startswith("heading") and 
            "Coding Standards" in block.get("content", "")
            for block in standards_blocks
        )
        if not has_coding_standards_heading:
            errors.append("[X] Missing 'Coding Standards' heading")
        else:
            checks_passed.append("[C] has 'Coding Standards' heading")
    
        # Check for numbered list items for languages
        has_numbered_list = any(
            block.get("type", "") == "numberedList"
            for block in standards_blocks
        )
        if not has_numbered_list:
            errors.append("[X] Missing numbered list items for different languages")
        else:
            checks_passed.append("[C] has numbered list items for different languages")
    
        # Check for Review Process heading
        has_review_heading = any(
            block.get("type", "").startswith("heading") and 
            "Review Process" in block.get("content", "")
            for block in standards_blocks
        )
        if not has_review_heading:
            errors.append("[X] Missing 'Review Process' heading")
        else:
            checks_passed.append("[C] has 'Review Process' heading")
    
        # Check for todo checklist items
        has_todo_items = any(
            block.get("type", "") == "todo"
            for block in standards_blocks
        )
        if not has_todo_items:
            errors.append("[X] Missing todo checklist items for code review steps")
        else:
            checks_passed.append("[C] has todo checklist items for code review steps")
    
        # Check for quote block
        has_quote = any(
            block.get("type", "") == "quote"
            for block in standards_blocks
        )
        if not has_quote:
            errors.append("[X] Missing quote block with inspiring message about code quality")
        else:
            checks_passed.append("[C] has quote block with inspiring message about code quality")
    
        # Check 6: Architecture-related page moved under Code Standards
        child_pages = _get_child_pages(final_state_backend, code_standards["_id"])
        has_architecture_child = any(
            "architecture" in page.get("title", "").lower()
            for page in child_pages
        )
        if not has_architecture_child:
            errors.append("[X] No architecture-related page found as child of Code Standards & Guidelines")
        else:
            checks_passed.append("[C] architecture-related page found as child of Code Standards & Guidelines")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_meeting_streamline(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate meeting documentation streamlining task."""
    errors: list[str] = []
    checks_passed: list[str] = []

    # Check that Meeting Notes was renamed to Meeting Hub with calendar icon
    # First check if page-3 exists and has title Meeting Hub
    try:
        page_3 = _find_page_by_id(final_state_backend, 'page-3')
        meeting_hub = None
        if page_3 and page_3.get('title') == 'Meeting Hub':
            meeting_hub = page_3
    
        if not meeting_hub:
            # Also check if there's a new page called Meeting Hub
            meeting_hub = _find_page_by_title(final_state_backend, 'Meeting Hub')
            if not meeting_hub:
                errors.append("[X] Meeting Hub page not found (original Meeting Notes should be renamed)")
            else:
                checks_passed.append("[C] Meeting Hub page found (original Meeting Notes should be renamed)")
    
        # Check for calendar icon
        icon = meeting_hub.get('icon', '')
        if '📅' not in icon and 'calendar' not in icon.lower() and '🗓' not in icon:
            errors.append("[X] Meeting Hub does not have a calendar icon")
        else:
            checks_passed.append("[C] Meeting Hub has a calendar icon")
    
        # Check for Q1 2024 Meeting Archive page (should be at root level, same as Meeting Hub)
        archive_page = _find_page_by_title(final_state_backend, 'Q1 2024 Meeting Archive')
        if not archive_page:
            errors.append("[X] Q1 2024 Meeting Archive page not found")
        else:
            checks_passed.append("[C] Q1 2024 Meeting Archive page found")
    
        # Archive should be at root level (no parent), same as Meeting Hub
        if archive_page.get('parentId'):
            errors.append("[X] Q1 2024 Meeting Archive should be at root level, not nested")
        else:
            checks_passed.append("[C] Q1 2024 Meeting Archive should be at root level, nested")
    
        # Check that at least one old meeting page was moved into the archive
        archive_children = _get_child_pages(final_state_backend, archive_page.get('_id'))
        if len(archive_children) < 1:
            errors.append("[X] No meeting pages found in Q1 2024 Meeting Archive")
        else:
            checks_passed.append("[C] meeting pages found in Q1 2024 Meeting Archive")
    
        # Check if Sprint Planning - Jan 15 is in the archive
        old_meeting_found = False
        for child in archive_children:
            if 'Sprint Planning' in child.get('title', '') and 'Jan' in child.get('title', ''):
                old_meeting_found = True
                break
    
        if not old_meeting_found:
            # At least one meeting page should be in archive
            if len(archive_children) == 0:
                errors.append("[X] Sprint Planning - Jan 15 or other old meeting pages should be moved to archive")
            else:
                checks_passed.append("[C] Sprint Planning - Jan 15 or other old meeting pages should be moved to archive")
    
        # Check for Current Meetings page
        current_meetings = _find_page_by_title(final_state_backend, 'Current Meetings')
        if not current_meetings:
            errors.append("[X] Current Meetings page not found")
        else:
            checks_passed.append("[C] Current Meetings page found")
    
        # Verify hierarchy is correct
        meeting_hub_id = meeting_hub.get('_id')
        archive_id = archive_page.get('_id')
        current_meetings_id = current_meetings.get('_id')
    
        # All should exist
        if not all([meeting_hub_id, archive_id, current_meetings_id]):
            errors.append("[X] Missing required pages in final state")
        else:
            checks_passed.append("[C] has required pages in final state")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_project_tracking_system_v2(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate project tracking system creation with dashboard and trackers."""
    errors: list[str] = []

    checks_passed = []

    # Check for Project Status Dashboard page with chart icon
    try:
        dashboard = _find_page_by_title(final_state_backend, "Project Status Dashboard")
        if not dashboard:
            errors.append("[X] Project Status Dashboard page not found")
        else:
            checks_passed.append("[C] Project Status Dashboard page found")
    
        # Check for chart icon
        icon = dashboard.get("icon", "")
        if "chart" not in icon.lower() and "📊" not in icon and "📈" not in icon and "📉" not in icon:
            errors.append("[X] Project Status Dashboard does not have a chart icon")
        else:
            checks_passed.append("[C] Project Status Dashboard created with chart icon")
    
        dashboard_id = dashboard.get("_id")
    
        # Check for tracker pages under the dashboard
        child_pages = _get_child_pages(final_state_backend, dashboard_id)
        tracker_pages = []
    
        # Look for specific tracker names
        expected_trackers = [
            "Q1 Initiative Tracker",
            "Feature Development Tracker"
        ]
    
        for tracker_name in expected_trackers:
            tracker = _find_page_by_title_pattern_and_parent(final_state_backend, tracker_name, dashboard.get("_id"))
            if tracker:
                tracker_pages.append(tracker)
    
        # Need at least 2 tracker pages
        if len(tracker_pages) < 2:
            errors.append(f"[X] Expected at least 2 tracker pages under dashboard, found {len(tracker_pages)}")
        else:
            checks_passed.append(f"[C] Found {len(tracker_pages)} tracker pages under dashboard")
    
        # Validate each tracker has required content
        for tracker in tracker_pages:
            tracker_id = tracker.get("_id")
            tracker_title = tracker.get("title", "")
            blocks = _get_blocks_for_page(final_state_backend, tracker_id)
        
            # Check for todo checklists
            todo_blocks = [b for b in blocks if b.get("type") == "todo"]
            if not todo_blocks:
                errors.append(f"[X] {tracker_title} does not contain any todo checklists")
            else:
                checks_passed.append(f"[C] {tracker_title} does contains any todo checklists")
        
            # Check for divider blocks
            divider_blocks = [b for b in blocks if b.get("type") == "divider"]
            if not divider_blocks:
                errors.append(f"[X] {tracker_title} does not contain any divider blocks")
            else:
                checks_passed.append(f"[C] {tracker_title} does contains any divider blocks")
        
            # Check for callout blocks
            callout_blocks = [b for b in blocks if b.get("type") == "callout"]
            if not callout_blocks:
                errors.append(f"[X] {tracker_title} does not contain any callout blocks")
            else:
                checks_passed.append(f"[C] {tracker_title} does contains any callout blocks")
        
            checks_passed.append(f"[C] {tracker_title} contains {len(todo_blocks)} todos, {len(divider_blocks)} dividers, {len(callout_blocks)} callouts")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_development_workflow_guide(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Development Workflow Guide creation from duplicated Engineering Wiki."""
    errors: list[str] = []
    checks_passed: list[str] = []

    
    # Check for Engineering Wiki (should still exist)
    try:
        engineering_wiki = _find_page_by_title(final_state_backend, "Engineering Wiki")
        if not engineering_wiki:
            errors.append("[X] Original Engineering Wiki page not found")
        else:
            checks_passed.append("[C] Original Engineering Wiki page found")
    
        # Check for Development Workflow Guide
        workflow_guide = _find_page_by_title(final_state_backend, "Development Workflow Guide")
        if not workflow_guide:
            errors.append("[X] Development Workflow Guide page not found")
        else:
            checks_passed.append("[C] Development Workflow Guide page found")
    
        # Check rocket icon
        icon = workflow_guide.get("icon", "")
        if "🚀" not in icon and "rocket" not in icon.lower():
            errors.append("[X] Development Workflow Guide does not have a rocket icon")
        else:
            checks_passed.append("[C] Development Workflow Guide has a rocket icon")
    
        # Get blocks for the workflow guide
        guide_blocks = _get_blocks_for_page(final_state_backend, workflow_guide.get("_id"))
        if not guide_blocks:
            errors.append("[X] Development Workflow Guide has no content blocks")
        else:
            checks_passed.append("[C] Development Workflow Guide has content blocks")
    
        # Check for required headings
        required_headings = ["Code Review Process", "Deployment Steps", "Testing Guidelines"]
        found_headings = []
        heading_blocks = [b for b in guide_blocks if b.get("type") in ["heading1", "heading2", "heading3", "heading_1", "heading_2", "heading_3"]]
    
        for required in required_headings:
            found = False
            for block in heading_blocks:
                if required.lower() in block.get("content", "").lower():
                    found_headings.append(required)
                    found = True
                    break
            if not found:
                errors.append(f"[X] Required heading '{required}' not found in Development Workflow Guide")
            else:
                checks_passed.append(f"[C] Required heading '{required}' found in Development Workflow Guide")
    
        # Check for numbered lists under each heading section
        numbered_list_count = len([b for b in guide_blocks if b.get("type") in ["numberedList", "numbered_list"]])
        if numbered_list_count < 3:  # At least one numbered list per section
            errors.append(f"[X] Expected numbered lists for process steps, found only {numbered_list_count}")
        else:
            checks_passed.append(f"[C] Expected numbered lists for process steps, found only {numbered_list_count}")
    
        # Check for callout blocks
        callout_blocks = [b for b in guide_blocks if b.get("type") in ["callout", "calloutBlock", "callout_block"]]
        if len(callout_blocks) == 0:
            errors.append("[X] No callout blocks found for warnings or best practices")
        else:
            checks_passed.append("[C] callout blocks found for warnings or best practices")
    
        # Check that original wiki content is preserved (should have similar base content)
        # We expect the duplicated page to have at least some content blocks
        if len(guide_blocks) < 10:  # Original had 12 blocks, new should have more with additions
            errors.append(f"[X] Expected substantial content from duplication and additions, found only {len(guide_blocks)} blocks")
        else:
            checks_passed.append(f"[C] Expected substantial content from duplication and additions, found only {len(guide_blocks)} blocks")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_sprint_kickoff_template(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Sprint Kickoff Template creation and organization."""
    errors: list[str] = []
    checks_passed: list[str] = []

    
    # Check that original Weekly Standup Template still exists unchanged
    try:
        original_template = _find_page_by_title(final_state_backend, "Weekly Standup Template")
        if not original_template:
            errors.append("[X] Original Weekly Standup Template not found")
        else:
            checks_passed.append("[C] Original Weekly Standup Template found")
    
        # Check for Sprint Kickoff Template
        sprint_template = _find_page_by_title(final_state_backend, "Sprint Kickoff Template")
        if not sprint_template:
            errors.append("[X] Sprint Kickoff Template not found")
        else:
            checks_passed.append("[C] Sprint Kickoff Template found")
    
        # Check for rocket icon
        icon = sprint_template.get("icon", "")
        if "rocket" not in icon.lower() and "🚀" not in icon:
            errors.append(f"[X] Sprint Kickoff Template does not have a rocket icon (found: '{icon}')")
        else:
            checks_passed.append(f"[C] Sprint Kickoff Template has a rocket icon (found: '{icon}')")
    
        # Check that Sprint Kickoff Template is under Project Documentation
        project_doc = _find_page_by_title(final_state_backend, "Project Documentation")
        if not project_doc:
            errors.append("[X] Project Documentation page not found")
        else:
            checks_passed.append("[C] Project Documentation page found")
    
        if sprint_template.get("parentId") != project_doc.get("_id"):
            errors.append("[X] Sprint Kickoff Template is not a child of Project Documentation")
        else:
            checks_passed.append("[C] Sprint Kickoff Template is a child of Project Documentation")
    
        # Check content structure
        sprint_blocks = _get_blocks_for_page(final_state_backend, sprint_template.get("_id"))
        if not sprint_blocks:
            errors.append("[X] Sprint Kickoff Template has no content")
        else:
            checks_passed.append("[C] Sprint Kickoff Template has content")
    
        # Sort blocks by order
        sprint_blocks.sort(key=lambda b: b.get("order", 0))
    
        # Count main headings
        main_headings = [b for b in sprint_blocks if b.get("type") in ["heading1", "heading2"]]
        if len(main_headings) < 2:
            errors.append(f"[X] Expected 2 main heading blocks, found {len(main_headings)}")
        else:
            checks_passed.append(f"[C] Found 2 main heading blocks as expected")
    
        # Check for Sprint Goals heading
        sprint_goals_heading = None
        for block in main_headings:
            if "sprint goals" in block.get("content", "").lower():
                sprint_goals_heading = block
                break
        if not sprint_goals_heading:
            errors.append("[X] No 'Sprint Goals' heading found")
        else:
            checks_passed.append("[C] 'Sprint Goals' heading found")
    
        # Check for Team Assignments heading
        team_assignments_heading = None
        for block in main_headings:
            if "team assignments" in block.get("content", "").lower():
                team_assignments_heading = block
                break
        if not team_assignments_heading:
            errors.append("[X] No 'Team Assignments' heading found")
        else:
            checks_passed.append("[C] 'Team Assignments' heading found")
    
        # Check for numbered list with 3-4 items
        numbered_lists = [b for b in sprint_blocks if b.get("type") == "numberedList"]
        if len(numbered_lists) < 3:
            errors.append(f"[X] Expected at least 3 numbered list items, found {len(numbered_lists)}")
        else:
            checks_passed.append(f"[C] Found at least 3 numbered list items ({len(numbered_lists)})")
    
        # Check for todo checklist with specific items
        todos = [b for b in sprint_blocks if b.get("type") == "todo"]
        if len(todos) < 3:
            errors.append(f"[X] Expected at least 3 todo items, found {len(todos)}")
        else:
            checks_passed.append(f"[C] Found at least 3 todo items ({len(todos)})")
    
        # Check for specific todo items
        required_todos = ["review backlog", "assign story points", "set sprint deadline"]
        todo_contents = [b.get("content", "").lower() for b in todos]
    
        for required in required_todos:
            found = False
            for content in todo_contents:
                if required in content:
                    found = True
                    break
            if not found:
                errors.append(f"[X] Missing required todo item: '{required}'")
            else:
                checks_passed.append(f"[C] has required todo item: '{required}'")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_template_reorganization(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate template collection cleanup and improvement."""
    errors: list[str] = []
    checks_passed: list[str] = []

    
    # Check for Templates Collection page with filing cabinet icon
    try:
        templates_collection = _find_page_by_title(final_state_backend, "Templates Collection")
        if not templates_collection:
            errors.append("[X] Templates Collection page not found")
        else:
            checks_passed.append("[C] Templates Collection page found")
    
        # Check filing cabinet icon
        icon = templates_collection.get("icon", "")
        if "filing" not in icon.lower() and "🗄" not in icon and "🗃" not in icon and "📁" not in icon:
            errors.append("[X] Templates Collection does not have a filing cabinet icon")
        else:
            checks_passed.append("[C] Templates Collection has a filing cabinet icon")
    
        # Check if Templates Collection is marked as favorite
        if not templates_collection.get("isFavorite", False):
            errors.append("[X] Templates Collection is not marked as favorite")
        else:
            checks_passed.append("[C] Templates Collection is marked as favorite")
    
        # Get all pages with 'template' in title (case insensitive)
        template_pages = _find_pages_by_title(final_state_backend, "template")
        if len(template_pages) < 4:  # At least 3 existing + 1 new master template
            errors.append(f"[X] Expected at least 4 template pages, found {len(template_pages)}")
        else:
            checks_passed.append(f"[C] Found at least 4 template pages ({len(template_pages)})")
    
        # Check for Master Project Template with briefcase icon
        master_template = _find_page_by_title(final_state_backend, "Master Project Template")
        if not master_template:
            errors.append("[X] Master Project Template not found")
        else:
            checks_passed.append("[C] Master Project Template found")
    
        # Check briefcase icon
        master_icon = master_template.get("icon", "")
        if "briefcase" not in master_icon.lower() and "💼" not in master_icon:
            errors.append("[X] Master Project Template does not have a briefcase icon")
        else:
            checks_passed.append("[C] Master Project Template has a briefcase icon")
    
        # Check all template pages are children of Templates Collection
        collection_id = templates_collection.get("_id")
        for template in template_pages:
            if template.get("parentId") != collection_id:
                errors.append(f"[X] Template '{template.get('title')}' is not under Templates Collection")
            else:
                checks_passed.append(f"[C] Template '{template.get('title')}' is under Templates Collection")
    
        # Validate Master Project Template content structure
        master_id = master_template.get("_id")
        master_blocks = _get_blocks_for_page(final_state_backend, master_id)
    
        if len(master_blocks) < 6:
            errors.append(f"[X] Master Project Template has insufficient content blocks: {len(master_blocks)}")
        else:
            checks_passed.append(f"[C] Master Project Template has insufficient content blocks: {len(master_blocks)}")
    
        # Check for required content types
        has_project_overview = False
        has_paragraph_after_overview = False
        has_goals_heading = False
        has_numbered_list = False
        has_timeline_heading = False
        has_todos = False
        has_resources_heading = False
        has_bulleted_list = False
        has_code_block = False
    
        # Track if we've seen the overview heading
        seen_overview = False
    
        for i, block in enumerate(master_blocks):
            block_type = block.get("type", "")
            content = block.get("content", "").lower()
        
            # Check for project overview heading
            if block_type in ["heading1", "heading2", "heading3", "heading_1", "heading_2", "heading_3"]:
                if "project overview" in content:
                    has_project_overview = True
                    seen_overview = True
        
            # Check for paragraph after overview
            if seen_overview and not has_paragraph_after_overview and block_type == "paragraph":
                has_paragraph_after_overview = True
        
            # Check for Project Goals section
            if block_type in ["heading1", "heading2", "heading3", "heading_1", "heading_2", "heading_3"]:
                if "project goals" in content:
                    has_goals_heading = True
        
            # Check for numbered list
            if block_type in ["numbered_list", "numberedList", "ordered_list"]:
                has_numbered_list = True
        
            # Check for Timeline & Milestones section
            if block_type in ["heading1", "heading2", "heading3", "heading_1", "heading_2", "heading_3"]:
                if "timeline" in content and "milestones" in content:
                    has_timeline_heading = True
        
            # Check for todo checkboxes
            if block_type == "todo":
                has_todos = True
        
            # Check for Resources & Links section
            if block_type in ["heading1", "heading2", "heading3", "heading_1", "heading_2", "heading_3"]:
                if "resources" in content and "links" in content:
                    has_resources_heading = True
        
            # Check for bulleted list
            if block_type in ["bulleted_list", "bulletedList", "unordered_list"]:
                has_bulleted_list = True
        
            # Check for code block
            if block_type in ["code", "codeBlock", "code_block"]:
                has_code_block = True
    
        # Validate all required content exists
        if not has_project_overview:
            errors.append("[X] Master Project Template missing project overview heading")
        else:
            checks_passed.append("[C] Master Project Template has project overview heading")
        if not has_paragraph_after_overview:
            errors.append("[X] Master Project Template missing paragraph placeholder after overview")
        else:
            checks_passed.append("[C] Master Project Template has paragraph placeholder after overview")
        if not has_goals_heading:
            errors.append("[X] Master Project Template missing 'Project Goals' section")
        else:
            checks_passed.append("[C] Master Project Template has 'Project Goals' section")
        if not has_numbered_list:
            errors.append("[X] Master Project Template missing numbered list in goals section")
        else:
            checks_passed.append("[C] Master Project Template has numbered list in goals section")
        if not has_timeline_heading:
            errors.append("[X] Master Project Template missing 'Timeline & Milestones' section")
        else:
            checks_passed.append("[C] Master Project Template has 'Timeline & Milestones' section")
        if not has_todos:
            errors.append("[X] Master Project Template missing todo checkboxes for key phases")
        else:
            checks_passed.append("[C] Master Project Template has todo checkboxes for key phases")
        if not has_resources_heading:
            errors.append("[X] Master Project Template missing 'Resources & Links' section")
        else:
            checks_passed.append("[C] Master Project Template has 'Resources & Links' section")
        if not has_bulleted_list:
            errors.append("[X] Master Project Template missing bulleted list placeholders")
        else:
            checks_passed.append("[C] Master Project Template has bulleted list placeholders")
        if not has_code_block:
            errors.append("[X] Master Project Template missing code block section for technical notes")
        else:
            checks_passed.append("[C] Master Project Template has code block section for technical notes")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_archive_hub_organization(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Archive Hub 2025 creation and archived pages organization."""
    errors: list[str] = []

    checks_passed = []
    
    # Check for Archive Hub 2025 page
    try:
        archive_hub = _find_page_by_title(final_state_backend, "Archive Hub 2025")
        if not archive_hub:
            errors.append("[X] Archive Hub 2025 page not found")
        else:
            checks_passed.append("[C] Archive Hub 2025 page found")
    
        # Check for folder icon
        icon = archive_hub.get("icon", "")
        if "folder" not in icon.lower() and "📁" not in icon and "🗂" not in icon and "📂" not in icon:
            errors.append("[X] Archive Hub 2025 does not have a folder icon")
        else:
            checks_passed.append("[C] Archive Hub 2025 created with folder icon")
    
        # Check that Archive Hub is marked as favorite
        if not archive_hub.get("isFavorite", False):
            errors.append("[X] Archive Hub 2025 is not marked as favorite")
        else:
            checks_passed.append("[C] Archive Hub 2025 marked as favorite")
    
        # Check for archive callout block
        hub_blocks = _get_blocks_for_page(final_state_backend, archive_hub["_id"])
        has_archive_callout = False
        for block in hub_blocks:
            if block.get("type") == "callout":
                content = block.get("content", "").lower()
                # Check if callout explains the hub's purpose
                if any(word in content for word in ["archive", "archived", "old", "content", "discovery", "organize", "hub"]):
                    has_archive_callout = True
                    break
    
        if not has_archive_callout:
            errors.append("[X] Archive Hub 2025 does not have an archive callout explaining its purpose")
        else:
            checks_passed.append("[C] Archive callout found explaining hub purpose")
    
        # Find all archived pages that are children of Archive Hub
        hub_id = archive_hub.get("_id")
        child_pages = _get_child_pages(final_state_backend, hub_id)
        archived_children = [p for p in child_pages if p.get("isArchived", False)]
    
        # Check that at least 4 archived pages are under Archive Hub
        if len(archived_children) < 4:
            errors.append(f"[X] Expected at least 4 archived pages under Archive Hub, found {len(archived_children)}")
        else:
            checks_passed.append(f"[C] Found {len(archived_children)} archived pages under Archive Hub")
    
        # Verify that archived pages maintain their original content and icons
        # Check a few known archived pages
        known_archived_titles = ["Old Project Notes", "Old Marketing Campaign", "Deprecated API Docs", 
                               "2023 Q4 Retrospective", "Legacy Code Review", "Old Brand Assets"]
    
        moved_pages = [p for p in archived_children if p.get("title") in known_archived_titles]
        if len(moved_pages) < 4:
            # Also accept if there are at least 4 archived pages total, even if titles differ
            if len(archived_children) >= 4:
                checks_passed.append("[C] At least 4 archived pages successfully moved under Archive Hub")
            else:
                errors.append(f"[X] Not enough archived pages found under Archive Hub (found {len(archived_children)})")
        else:
            checks_passed.append(f"[C] Successfully moved {len(moved_pages)} known archived pages")
    
        # Verify pages maintain their content - check if Old Project Notes still has its blocks
        old_project_notes = next((p for p in archived_children if p.get("title") == "Old Project Notes"), None)
        if old_project_notes:
            notes_blocks = _get_blocks_for_page(final_state_backend, old_project_notes["_id"])
            if len(notes_blocks) > 0:
                checks_passed.append("[C] Archived pages maintain their original content")
    
        # Verify archived pages maintain their icons
        pages_with_icons = [p for p in archived_children if p.get("icon")]
        if len(pages_with_icons) > 0:
            checks_passed.append("[C] Archived pages maintain their original icons")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_comprehensive_team_resource_center(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate comprehensive team resource center creation."""
    errors: list[str] = []

    checks_passed = []

    # Check 1: Team Resource Hub exists with people icon and is marked as favorite
    try:
        hub = _find_page_by_title(final_state_backend, "Team Resource Hub")
        if not hub:
            errors.append("[X] Team Resource Hub page not found")
        else:
            checks_passed.append("[C] Team Resource Hub page found")
    
        hub_id = hub.get("_id")
    
        # Check for people icon (could be 👥, 👫, 👬, 👭, 🧑‍🤝‍🧑, or text containing 'people')
        icon = hub.get("icon", "")
        if not ("👥" in icon or "👫" in icon or "👬" in icon or "👭" in icon or 
                "🧑‍🤝‍🧑" in icon or "people" in icon.lower()):
            errors.append("[X] Team Resource Hub does not have a people icon")
        else:
            checks_passed.append("[C] Team Resource Hub has a people icon")
    
        # Check if marked as favorite
        if not hub.get("isFavorite", False):
            errors.append("[X] Team Resource Hub is not marked as favorite")
        else:
            checks_passed.append("[C] Team Resource Hub is marked as favorite")
    
        checks_passed.append("[C] Team Resource Hub created with people icon and marked as favorite")

        # Check 2: Team Directory is moved under Team Resource Hub
        team_directory = _find_page_by_title(final_state_backend, "Team Directory")
        if not team_directory:
            errors.append("[X] Team Directory page not found")
        else:
            checks_passed.append("[C] Team Directory page found")
    
        if team_directory.get("parentId") != hub_id:
            errors.append("[X] Team Directory is not under Team Resource Hub")
        else:
            checks_passed.append("[C] Team Directory is under Team Resource Hub")
    
        checks_passed.append("[C] Team Directory moved under Team Resource Hub")

        # Check 3: Three new sub-pages exist under the hub
        required_children = ["Team Guidelines", "Contact Information", "Meeting Schedules"]
        child_pages = _get_child_pages(final_state_backend, hub_id)
        child_titles = [p.get("title", "") for p in child_pages]
    
        for required_title in required_children:
            if required_title not in child_titles:
                errors.append(f"[X] Required sub-page '{required_title}' not found under Team Resource Hub")
            else:
                checks_passed.append(f"[C] Required sub-page '{required_title}' found under Team Resource Hub")
    
        checks_passed.append("[C] All required sub-pages created: Team Guidelines, Contact Information, Meeting Schedules")

        # Check 4: Team Guidelines page has required content
        team_guidelines = _find_page_by_title_pattern_and_parent(final_state_backend, "Team Guidelines", hub.get("_id"))
        if not team_guidelines:
            errors.append("[X] Team Guidelines page not found under Team Resource Hub")
        else:
            checks_passed.append("[C] Team Guidelines page found under Team Resource Hub")
    
        guidelines_id = team_guidelines.get("_id")
        guidelines_blocks = _get_blocks_for_page(final_state_backend, guidelines_id)
    
        # Check for heading blocks
        heading_blocks = [b for b in guidelines_blocks if b.get("type", "").startswith("heading")]
        if len(heading_blocks) == 0:
            errors.append("[X] Team Guidelines page does not contain any heading blocks")
        else:
            checks_passed.append("[C] Team Guidelines page does contains any heading blocks")
    
        # Check for numbered list blocks
        numbered_list_blocks = [b for b in guidelines_blocks if b.get("type") == "numberedList"]
        if len(numbered_list_blocks) == 0:
            errors.append("[X] Team Guidelines page does not contain any numbered list blocks")
        else:
            checks_passed.append("[C] Team Guidelines page does contains any numbered list blocks")
    
        # Check for quote blocks
        quote_blocks = [b for b in guidelines_blocks if b.get("type") == "quote"]
        if len(quote_blocks) == 0:
            errors.append("[X] Team Guidelines page does not contain any quote blocks")
        else:
            checks_passed.append("[C] Team Guidelines page does contains any quote blocks")
    
        checks_passed.append(f"[C] Team Guidelines populated with {len(heading_blocks)} headings, {len(numbered_list_blocks)} numbered lists, and {len(quote_blocks)} quote blocks")

        # Check 5: All pages are properly organized under the hub
        hub_children = _get_child_pages(final_state_backend, hub_id)
        if len(hub_children) < 4:  # Team Directory + 3 new pages
            errors.append(f"[X] Expected at least 4 pages under Team Resource Hub, found {len(hub_children)}")
        else:
            checks_passed.append(f"[C] Found at least 4 pages under Team Resource Hub ({len(hub_children)})")
    
        checks_passed.append("[C] All pages properly organized under Team Resource Hub")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_quarterly_review_organization(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate quarterly review system organization."""
    errors: list[str] = []

    checks_passed = []
    
    # Check for Quarterly Reviews page
    try:
        quarterly_reviews = _find_page_by_title(final_state_backend, "Quarterly Reviews")
        if not quarterly_reviews:
            errors.append("[X] Quarterly Reviews page not found")
        else:
            checks_passed.append("[C] Quarterly Reviews page found")
    
        # Check for calendar icon
        icon = quarterly_reviews.get("icon", "")
        if "calendar" not in icon.lower() and "📅" not in icon and "🗓️" not in icon and "📆" not in icon:
            errors.append("[X] Quarterly Reviews does not have a calendar icon")
        else:
            checks_passed.append("[C] Quarterly Reviews page created with calendar icon")
    
        quarterly_reviews_id = quarterly_reviews.get("_id")
    
        # Check for Q1 2024 Archive sub-page
        q1_archive = _find_page_by_title_pattern_and_parent(final_state_backend, "Q1 2024 Archive", quarterly_reviews.get("_id"))
        if not q1_archive:
            errors.append("[X] Q1 2024 Archive sub-page not found under Quarterly Reviews")
        else:
            checks_passed.append("[C] Q1 2024 Archive sub-page created")
    
        # Check for Q2 2024 Archive sub-page
        q2_archive = _find_page_by_title_pattern_and_parent(final_state_backend, "Q2 2024 Archive", quarterly_reviews.get("_id"))
        if not q2_archive:
            errors.append("[X] Q2 2024 Archive sub-page not found under Quarterly Reviews")
        else:
            checks_passed.append("[C] Q2 2024 Archive sub-page created")
    
        # Check if Q1 Goals page was moved to Q1 Archive
        q1_goals = _find_page_by_title(final_state_backend, "Q1 Goals")
        if q1_goals:
            if q1_goals.get("parentId") != q1_archive.get("_id"):
                errors.append("[X] Q1 Goals page was not moved to Q1 2024 Archive")
            else:
                checks_passed.append("[C] Q1 Goals moved to Q1 2024 Archive")
    
        # Check if Q2 Goals page was moved to Q2 Archive
        q2_goals = _find_page_by_title(final_state_backend, "Q2 Goals")
        if q2_goals:
            if q2_goals.get("parentId") != q2_archive.get("_id"):
                errors.append("[X] Q2 Goals page was not moved to Q2 2024 Archive")
            else:
                checks_passed.append("[C] Q2 Goals moved to Q2 2024 Archive")
    
        # Check Q1 Archive content (callout, divider, todo blocks)
        q1_blocks = _get_blocks_for_page(final_state_backend, q1_archive.get("_id"))
        q1_block_types = [block.get("type") for block in q1_blocks]
    
        if "callout" not in q1_block_types:
            errors.append("[X] Q1 2024 Archive missing callout block with quarterly summary")
        else:
            checks_passed.append("[C] Q1 2024 Archive has callout block with quarterly summary")
    
        if "divider" not in q1_block_types:
            errors.append("[X] Q1 2024 Archive missing divider block")
        else:
            checks_passed.append("[C] Q1 2024 Archive has divider block")
    
        if "todo" not in q1_block_types:
            errors.append("[X] Q1 2024 Archive missing todo checklist blocks")
        else:
            checks_passed.append("[C] Q1 2024 Archive has todo checklist blocks")
    
        checks_passed.append("[C] Q1 2024 Archive has callout, divider, and todo blocks")
    
        # Check Q2 Archive content (callout, divider, todo blocks)
        q2_blocks = _get_blocks_for_page(final_state_backend, q2_archive.get("_id"))
        q2_block_types = [block.get("type") for block in q2_blocks]
    
        if "callout" not in q2_block_types:
            errors.append("[X] Q2 2024 Archive missing callout block with quarterly summary")
        else:
            checks_passed.append("[C] Q2 2024 Archive has callout block with quarterly summary")
    
        if "divider" not in q2_block_types:
            errors.append("[X] Q2 2024 Archive missing divider block")
        else:
            checks_passed.append("[C] Q2 2024 Archive has divider block")
    
        if "todo" not in q2_block_types:
            errors.append("[X] Q2 2024 Archive missing todo checklist blocks")
        else:
            checks_passed.append("[C] Q2 2024 Archive has todo checklist blocks")
    
        checks_passed.append("[C] Q2 2024 Archive has callout, divider, and todo blocks")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_meeting_documentation_organization(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate meeting documentation organization with archive creation."""
    errors: list[str] = []
    checks_passed: list[str] = []

    
    # Check for Meeting Archive - Q1 2024 page
    try:
        archive_page = _find_page_by_title(final_state_backend, "Meeting Archive - Q1 2024")
        if not archive_page:
            errors.append("[X] Meeting Archive - Q1 2024 page not found")
        else:
            checks_passed.append("[C] Meeting Archive - Q1 2024 page found")
    
        # Check for calendar icon
        icon = archive_page.get("icon", "")
        if "calendar" not in icon.lower() and "📅" not in icon and "🗓" not in icon:
            errors.append("[X] Meeting Archive - Q1 2024 does not have a calendar icon")
        else:
            checks_passed.append("[C] Meeting Archive - Q1 2024 has a calendar icon")
    
        # Check if marked as favorite
        if not archive_page.get("isFavorite", False):
            errors.append("[X] Meeting Archive - Q1 2024 is not marked as favorite")
        else:
            checks_passed.append("[C] Meeting Archive - Q1 2024 is marked as favorite")
    
        # Find meeting pages that should be moved under archive (Sprint or Retrospective in title)
        sprint_pages_result = final_state_backend.query({
            "collection": "pages",
            "filter": {"title": {"$regex": "Sprint", "$options": "i"}}
        })
        retro_pages_result = final_state_backend.query({
            "collection": "pages",
            "filter": {"title": {"$regex": "Retrospective", "$options": "i"}}
        })
        sprint_pages = sprint_pages_result if isinstance(sprint_pages_result, list) else []
        retro_pages = retro_pages_result if isinstance(retro_pages_result, list) else []
        meeting_pages = sprint_pages + [p for p in retro_pages if p not in sprint_pages]
    
        # Check that at least 2 meeting pages are children of the archive
        archive_id = archive_page.get("_id")
        child_meeting_pages = [p for p in meeting_pages if p.get("parentId") == archive_id]
    
        if len(child_meeting_pages) < 2:
            errors.append(f"[X] Expected at least 2 meeting pages as children of archive, found {len(child_meeting_pages)}")
        else:
            checks_passed.append(f"[C] Found at least 2 meeting pages as children of archive ({len(child_meeting_pages)})")
    
        # Check that archive page has structured content
        archive_blocks = _get_blocks_for_page(final_state_backend, archive_id)
        if len(archive_blocks) < 3:
            errors.append("[X] Meeting Archive page lacks structured content (needs heading sections and bullet list summary)")
        else:
            checks_passed.append("[C] Meeting Archive page lacks structured content (needs heading sections and bullet list summary)")
    
        # Check for heading sections
        heading_blocks = [b for b in archive_blocks if b.get("type", "") in ["heading1", "heading2", "heading3", "heading_1", "heading_2", "heading_3"]]
        if len(heading_blocks) < 1:
            errors.append("[X] Meeting Archive page needs heading sections for different meeting types")
        else:
            checks_passed.append("[C] Meeting Archive page needs heading sections for different meeting types")
    
        # Check for bullet list summary
        bullet_blocks = [b for b in archive_blocks if b.get("type", "") in ["bullet_list", "bulletedList", "bulleted_list", "bulleted-list"]]
        if len(bullet_blocks) < 1:
            errors.append("[X] Meeting Archive page needs bullet points listing meeting types")
        else:
            checks_passed.append("[C] Meeting Archive page needs bullet points listing meeting types")
    
        # Verify that original meeting pages retain their content
        for meeting_page in child_meeting_pages:
            page_id = meeting_page.get("_id")
            # Check that page still has its original metadata
            if not meeting_page.get("createdAt") or not meeting_page.get("createdBy"):
                errors.append(f"[X] Meeting page {meeting_page.get('title')} lost its metadata")
            else:
                checks_passed.append(f"[C] Meeting page {meeting_page.get('title')} lost its metadata")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_project_management_setup(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate comprehensive project management workspace setup."""
    errors: list[str] = []
    checks_passed: list[str] = []

    
    # Check for Project Hub page with building icon
    try:
        project_hub = _find_page_by_title(final_state_backend, "Project Hub")
        if not project_hub:
            errors.append("[X] Project Hub page not found")
        else:
            checks_passed.append("[C] Project Hub page found")
    
        # Check for building icon
        icon = project_hub.get("icon", "")
        if "building" not in icon.lower() and "🏢" not in icon and "🏗️" not in icon and "🏛️" not in icon:
            errors.append("[X] Project Hub does not have a building icon")
        else:
            checks_passed.append("[C] Project Hub has a building icon")
    
        # Check if Project Hub is marked as favorite
        if not project_hub.get("isFavorite", False):
            errors.append("[X] Project Hub is not marked as favorite")
        else:
            checks_passed.append("[C] Project Hub is marked as favorite")
    
        # Get blocks for Project Hub
        hub_id = project_hub.get("_id")
        hub_blocks = _get_blocks_for_page(final_state_backend, hub_id)
    
        # Check for required sections (headings)
        headings = [block for block in hub_blocks if block.get("type", "").startswith("heading")]
        heading_contents = [block.get("content", "").lower() for block in headings]
    
        # Check for the three main sections
        has_active_projects = any("active projects" in content for content in heading_contents)
        has_planning_templates = any("planning templates" in content for content in heading_contents)
        has_guidelines = any("guidelines" in content for content in heading_contents)
    
        if not has_active_projects:
            errors.append("[X] Missing 'Active Projects' section heading")
        else:
            checks_passed.append("[C] has 'Active Projects' section heading")
        if not has_planning_templates:
            errors.append("[X] Missing 'Planning Templates' section heading")
        else:
            checks_passed.append("[C] has 'Planning Templates' section heading")
        if not has_guidelines:
            errors.append("[X] Missing 'Guidelines' section heading")
        else:
            checks_passed.append("[C] has 'Guidelines' section heading")
    
        # Check for at least 3 heading blocks
        if len(headings) < 3:
            errors.append(f"[X] Expected at least 3 heading blocks, found {len(headings)}")
        else:
            checks_passed.append(f"[C] Found at least 3 heading blocks ({len(headings)})")
    
        # Check for at least 2 divider blocks
        dividers = [block for block in hub_blocks if block.get("type") == "divider"]
        if len(dividers) < 2:
            errors.append(f"[X] Expected at least 2 divider blocks, found {len(dividers)}")
        else:
            checks_passed.append(f"[C] Found at least 2 divider blocks ({len(dividers)})")
    
        # Check for duplicated Weekly Standup Template under Project Hub
        child_pages = _get_child_pages(final_state_backend, hub_id)
    
        # Look for a page with 'Weekly Standup' in title that is a child of Project Hub
        weekly_standup_child = None
        for child in child_pages:
            if "weekly standup" in child.get("title", "").lower():
                weekly_standup_child = child
                break
    
        if not weekly_standup_child:
            errors.append("[X] No duplicated Weekly Standup Template found under Project Hub")
        else:
            checks_passed.append("[C] duplicated Weekly Standup Template found under Project Hub")
    
        # Verify it's a duplicate (should be different from the original page-9)
        original_standup = _find_page_by_title(final_state_backend, "Weekly Standup Template")
        if weekly_standup_child.get("_id") == "page-9":
            errors.append("[X] Weekly Standup Template was not duplicated (still original page)")
        else:
            checks_passed.append("[C] Weekly Standup Template was duplicated (still original page)")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_project_documentation_system(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate project documentation system creation and organization."""
    errors: list[str] = []
    checks_passed: list[str] = []

    
    # Check for Project Documentation Hub
    try:
        hub = _find_page_by_title(final_state_backend, "Project Documentation Hub")
        if not hub:
            errors.append("[X] Project Documentation Hub page not found")
        else:
            checks_passed.append("[C] Project Documentation Hub page found")
    
        # Check for folder icon
        icon = hub.get("icon", "")
        if "folder" not in icon.lower() and "📁" not in icon and "📂" not in icon:
            errors.append("[X] Project Documentation Hub does not have a folder icon")
        else:
            checks_passed.append("[C] Project Documentation Hub has a folder icon")
    
        # Check if marked as favorite
        if not hub.get("isFavorite", False):
            errors.append("[X] Project Documentation Hub is not marked as favorite")
        else:
            checks_passed.append("[C] Project Documentation Hub is marked as favorite")
    
        # Check for exactly 2 child pages
        hub_id = hub.get("_id")
        child_pages = _get_child_pages(final_state_backend, hub_id)
        if len(child_pages) != 2:
            errors.append(f"[X] Expected exactly 2 child pages, found {len(child_pages)}")
        else:
            checks_passed.append(f"[C] Expected exactly 2 child pages, found {len(child_pages)}")
    
        # Check for Weekly Standup Template as child
        weekly_template = None
        project_template = None
    
        for child in child_pages:
            if child.get("title") == "Weekly Standup Template":
                weekly_template = child
            elif child.get("title") == "Project Status Template":
                project_template = child
    
        if not weekly_template:
            errors.append("[X] Weekly Standup Template not found as child of Documentation Hub")
        else:
            checks_passed.append("[C] Weekly Standup Template found as child of Documentation Hub")
    
        if not project_template:
            errors.append("[X] Project Status Template not found as child of Documentation Hub")
        else:
            checks_passed.append("[C] Project Status Template found as child of Documentation Hub")
    
        # Check Project Status Template has project icon
        project_icon = project_template.get("icon", "")
        if ("project" not in project_icon.lower() and 
            "📊" not in project_icon and 
            "🗂️" not in project_icon and 
            "📈" not in project_icon and
            "💼" not in project_icon):
            errors.append("[X] Project Status Template does not have a project-related icon")
        else:
            checks_passed.append("[C] Project Status Template has a project-related icon")
    
        # Check hub content
        hub_blocks = _get_blocks_for_page(final_state_backend, hub_id)
        if not hub_blocks:
            errors.append("[X] Project Documentation Hub has no content")
        else:
            checks_passed.append("[C] Project Documentation Hub has content")
    
        # Check for introduction heading
        has_intro_heading = any(
            block.get("type") in ["heading1", "heading2", "heading_1", "heading_2"] and
            any(word in block.get("content", "").lower() for word in ["introduction", "intro", "welcome", "documentation", "hub"])
            for block in hub_blocks
        )
        if not has_intro_heading:
            errors.append("[X] No introduction heading found in Documentation Hub")
        else:
            checks_passed.append("[C] introduction heading found in Documentation Hub")
    
        # Check for bulleted list
        has_bullet_list = any(
            block.get("type") in ["bullet", "bulleted_list", "bullet_list"]
            for block in hub_blocks
        )
        if not has_bullet_list:
            errors.append("[X] No bulleted list found in Documentation Hub")
        else:
            checks_passed.append("[C] bulleted list found in Documentation Hub")
    
        # Check for divider
        has_divider = any(
            block.get("type") == "divider"
            for block in hub_blocks
        )
        if not has_divider:
            errors.append("[X] No divider block found in Documentation Hub")
        else:
            checks_passed.append("[C] divider block found in Documentation Hub")
    
        # Verify bullet list contains template names
        bullet_blocks = [b for b in hub_blocks if b.get("type") in ["bullet", "bulleted_list", "bullet_list"]]
        template_names_found = []
        for block in bullet_blocks:
            content = block.get("content", "").lower()
            if "weekly standup template" in content:
                template_names_found.append("Weekly Standup Template")
            if "project status template" in content:
                template_names_found.append("Project Status Template")
    
        if len(template_names_found) < 2:
            errors.append("[X] Bulleted list does not contain both template names")
        else:
            checks_passed.append("[C] Bulleted list does contains both template names")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

    # -----------------------------------------------------------------------------
    # Task: content-lifecycle-management
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_content_lifecycle_management(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate comprehensive content lifecycle management system.
    
    Success criteria:
    1. Content Governance Hub created with 4 sections
    2. All published pages audited and review tracking created
    3. Style guides created for multiple content types through duplication
    4. Content organized by update recency
    5. Complex permission matrix implemented
    6. Audit reports created
    7. Publishing metadata enhanced with review schedules
    8. 10+ published pages managed with governance workflow
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    # 1. Validate Content Governance Hub exists with 4 sections
    try:
        governance_hub = _find_page_by_title(final_state_backend, "Content Governance Hub")
        if not governance_hub:
            errors.append("[X] Content Governance Hub page not found")
        else:
            checks_passed.append("[C] Content Governance Hub page found")
    
        required_sections = [
            "Active Publications",
            "Review Queue", 
            "Archive Pipeline",
            "Content Standards"
        ]
    
        # for section in required_sections:
        #     success, error = _validate_pages_contain_text(all_pages, all_blocks, [governance_hub.get("_id")], section)
        #     if not success:
        #         return 0.0, f"Content Governance Hub missing section: {section}"
        success, error_msg, found_sections =  _validate_page_structure(
            final_state_backend, governance_hub, required_sections
        )
        if not success:
            errors.append(f"[X] Content Governance Hub missing sections: {error_msg}")
        else:
            checks_passed.append(f"[C] Content Governance Hub has sections: {error_msg}")
    
        # 2. Validate all published pages are audited and have review tracking
        published_pages_result = final_state_backend.query({
            "collection": "pages",
            "filter": {"isPublished": True}
        })
        published_pages = published_pages_result if isinstance(published_pages_result, list) else []

        if len(published_pages) < 10:
            errors.append(f"[X] Expected at least 10 published pages, found {len(published_pages)}")
        else:
            checks_passed.append(f"[C] Found at least 10 published pages ({len(published_pages)})")

        # Get pages with review keywords in title for review tracking check
        review_pages_result = final_state_backend.query({
            "collection": "pages",
            "filter": {"title": {"$regex": "review|tracking|audit", "$options": "i"}}
        })
        review_keyword_pages = review_pages_result if isinstance(review_pages_result, list) else []

        # Check that review tracking pages exist for published pages
        # Review tracking pages should reference the published page or be linked
        review_tracking_count = 0
        for published_page in published_pages:
            published_title = published_page.get("title", "")
            # Look for review tracking pages - could be child pages or pages with "review" in title
            # that reference this published page
            review_keywords = ["review", "tracking", "audit"]
            found_review = False

            # Check if there's a child page with review-related title
            child_pages = _get_child_pages(final_state_backend, published_page.get("_id"))
            for child in child_pages:
                child_title = child.get("title", "").lower()
                if any(keyword in child_title for keyword in review_keywords):
                    found_review = True
                    break

            # Also check for pages that might link to this published page
            if not found_review:
                # Look for pages with review in title that might be tracking pages
                for page in review_keyword_pages:
                    # Check if blocks reference the published page
                    blocks = _get_blocks_for_page(final_state_backend, page.get("_id"))
                    for block in blocks:
                        content = str(block.get("content", "")).lower()
                        if published_title.lower() in content:
                            found_review = True
                            break
                    if found_review:
                        break

            if found_review:
                review_tracking_count += 1

        if review_tracking_count < len(published_pages) * 0.8:  # At least 80% should have review tracking
            errors.append(f"[X] Expected review tracking for most published pages, found {review_tracking_count}/{len(published_pages)}")
        else:
            checks_passed.append(f"[C] Expected review tracking for most published pages, found {review_tracking_count}/{len(published_pages)}")

        # 3. Validate style guides created through duplication of Brand Guidelines
        brand_guidelines = _find_page_by_title(final_state_backend, "Brand Guidelines")
        if not brand_guidelines:
            errors.append("[X] Brand Guidelines page not found (needed for duplication)")
        else:
            checks_passed.append("[C] Brand Guidelines page found (needed for duplication)")
    
        # Look for duplicated style guide pages (should have similar titles/content)
        style_guide_result = final_state_backend.query({
            "collection": "pages",
            "filter": {"title": {"$regex": "style guide|content style|writing guide|editorial guide", "$options": "i"}}
        })
        style_guide_pages = style_guide_result if isinstance(style_guide_result, list) else []
        # Exclude the original Brand Guidelines
        style_guides_found = [p for p in style_guide_pages if p.get("_id") != brand_guidelines.get("_id")]

        if len(style_guides_found) < 2:
            errors.append(f"[X] Expected at least 2 style guide pages created through duplication, found {len(style_guides_found)}")
        else:
            checks_passed.append(f"[C] Found at least 2 style guide pages created through duplication ({len(style_guides_found)})")

        # 4. Validate content organized by update recency
        # Check if there are pages or blocks that organize content by update dates
        # Look for pages with organization-related content (dates, sorting, etc.)
        organization_keywords = ["recent", "updated", "last modified", "date", "chronological"]
        has_organization = False

        # Check governance hub and its children for organization content
        hub_blocks = _get_blocks_for_page(final_state_backend, governance_hub.get("_id"))
        for block in hub_blocks:
            content = str(block.get("content", "")).lower()
            if any(keyword in content for keyword in organization_keywords):
                has_organization = True
                break

        # # Also check child sections
        for section_title in found_sections:
            section_page = _find_page_by_title_pattern_and_parent(final_state_backend, section_title, governance_hub.get("_id"))
            if section_page:
                section_blocks = _get_blocks_for_page(final_state_backend, section_page.get("_id"))
                for block in section_blocks:
                    content = str(block.get("content", "")).lower()
                    if any(keyword in content for keyword in organization_keywords):
                        has_organization = True
                        break
                if has_organization:
                    break
    
        if not has_organization:
            errors.append("[X] Content organization by update recency not found")
        else:
            checks_passed.append("[C] Content organization by update recency found")
    
        # 5. Validate complex permission matrix
        # Check that different pages have different permission levels:
        # - Drafts should have "edit" access for creators
        # - Review queue items should have "comment" access for reviewers  
        # - Only managers can publish/unpublish (this is harder to validate directly,
        #   but we can check that published pages have appropriate permissions)
    
        # Look for pages with "draft" in title or content
        draft_pages_result = final_state_backend.query({
            "collection": "pages",
            "filter": {"title": {"$regex": "draft", "$options": "i"}}
        })
        draft_pages = draft_pages_result if isinstance(draft_pages_result, list) else []

        # Find Review Queue section page
        review_queue_section = _find_page_by_title_pattern_and_parent(final_state_backend, "Review Queue", governance_hub.get("_id"))
        # Review queue pages are either pages with "review" in title or children of Review Queue section
        review_pages_result = final_state_backend.query({
            "collection": "pages",
            "filter": {"title": {"$regex": "review", "$options": "i"}}
        })
        review_queue_pages = review_pages_result if isinstance(review_pages_result, list) else []
        # Add children of Review Queue section if it exists
        if review_queue_section:
            review_section_children = _get_child_pages(final_state_backend, review_queue_section.get("_id"))
            for child in review_section_children:
                if child not in review_queue_pages:
                    review_queue_pages.append(child)
    
        # Check that draft pages have edit access
        draft_with_edit = 0
        for draft in draft_pages[:3]:  # Check first 3 drafts
            if _validate_access_levels(draft, ["edit"])[0]:
                draft_with_edit += 1
    
        # Check that review queue pages have comment access
        review_with_comment = 0
        for review_page in review_queue_pages[:3]:  # Check first 3 review pages
            if _validate_access_levels(review_page, ["comment"])[0]:
                review_with_comment += 1
    
        if draft_with_edit == 0 and len(draft_pages) > 0:
            errors.append("[X] Draft pages should have edit access for creators")
        else:
            checks_passed.append("[C] Draft pages should have edit access for creators")
    
        if review_with_comment == 0 and len(review_queue_pages) > 0:
            errors.append("[X] Review queue pages should have comment access for reviewers")
        else:
            checks_passed.append("[C] Review queue pages should have comment access for reviewers")
    
        # 6. Validate audit reports created
        audit_report_result = final_state_backend.query({
            "collection": "pages",
            "filter": {"title": {"$regex": "audit report|content audit|audit|report", "$options": "i"}}
        })
        audit_report_pages = audit_report_result if isinstance(audit_report_result, list) else []
        audit_reports_found = []

        for page in audit_report_pages:
            # Check if it has content (blocks)
            blocks = _get_blocks_for_page(final_state_backend, page.get("_id"))
            if len(blocks) > 0:
                audit_reports_found.append(page)

        if len(audit_reports_found) == 0:
            errors.append("[X] No audit reports found")
        else:
            checks_passed.append("[C] audit reports found")
    
        # 7. Validate publishing metadata enhanced with review schedules
        # Check that published pages have review schedule information in metadata
        pages_with_review_schedule = 0
        review_schedule_keywords = ["review schedule", "next review", "review date", "review cycle"]
    
        for published_page in published_pages:
            # Check publishedMetadata for review schedule info
            published_metadata = published_page.get("publishedMetadata", {})
            if isinstance(published_metadata, dict):
                # Check if there are additional fields indicating review schedule
                # (this might be in a custom field or in the metadata structure)
                metadata_str = str(published_metadata).lower()
                if any(keyword in metadata_str for keyword in review_schedule_keywords):
                    pages_with_review_schedule += 1
                    continue
        
            # Also check blocks on the page for review schedule mentions
            blocks = _get_blocks_for_page(final_state_backend, published_page.get("_id"))
            for block in blocks:
                content = str(block.get("content", "")).lower()
                if any(keyword in content for keyword in review_schedule_keywords):
                    pages_with_review_schedule += 1
                    break
    
        if pages_with_review_schedule < len(published_pages) * 0.5:  # At least 50% should have review schedules
            errors.append(f"[X] Expected review schedules for most published pages, found {pages_with_review_schedule}/{len(published_pages)}")
        else:
            checks_passed.append(f"[C] Expected review schedules for most published pages, found {pages_with_review_schedule}/{len(published_pages)}")
    
        # 8. Validate 10+ published pages managed (already checked above)
    
        # All validations passed
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

    # -----------------------------------------------------------------------------
    # Task: meeting-documentation-structure
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_meeting_documentation_structure(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate meeting documentation structure."""
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Validate new 'Team Meetings 2024' page exists with calendar icon and is marked as favorite
    try:
        team_meetings_2024 = _find_page_by_title(final_state_backend, "Team Meetings 2024")
        if not team_meetings_2024:
            errors.append("[X] Team Meetings 2024 page not found")
        else:
            checks_passed.append("[C] Team Meetings 2024 page found")
    
        # 2. Validate existing meeting note pages are moved as children under the archive
        meeting_notes_pages = _find_pages_by_title(final_state_backend, "meeting notes")
        if len(meeting_notes_pages) == 0:
            errors.append("[X] No meeting note pages found")
        else:
            checks_passed.append("[C] meeting note pages found")
    
        # 3. Validate new 'Meeting Notes' template page exists with 4 structured sections containing appropriate block types (headings, lists, todos)
        meeting_notes_template = _find_page_by_title(final_state_backend, "Meeting Notes")
        if not meeting_notes_template:
            errors.append("[X] Meeting Notes template page not found")
        else:
            checks_passed.append("[C] Meeting Notes template page found")
    
        # 4. Validate 4 structured sections as blocks/content in the page
        required_sections = [
            "Agenda",
            "Discussion Points",
            "Action Items",
            "Next Steps"
        ]

        template_id = meeting_notes_template.get("_id")

        # Validate each section exists in the page content (case-insensitive)
        for section in required_sections:
            success, error = _validate_pages_contain_text(
                final_state_backend, [template_id], section
            )
            if not success:
                errors.append(f"[X] Meeting Notes template missing section: {section}")
            else:
                checks_passed.append(f"[C] Meeting Notes template has section: {section}")

        found_sections = required_sections

        # All validations passed
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

    # -----------------------------------------------------------------------------
    # Task: workspace-orientation-guide
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_workspace_orientation_guide(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate workspace orientation guide."""
    errors: list[str] = []
    checks_passed: list[str] = []

    # 1. Validate new 'Workspace Navigation Guide' page exists with compass icon
    try:
        workspace_navigation_guide = _find_page_by_title(final_state_backend, "Workspace Navigation Guide")
        if not workspace_navigation_guide:
            errors.append("[X] Workspace Navigation Guide page not found")
        else:
            checks_passed.append("[C] Workspace Navigation Guide page found")

        # 2. Validate 'Workspace Navigation Guide' page is a child of 'Getting Started' page
        getting_started = _find_page_by_title(final_state_backend, "Getting Started")
        if not getting_started:
            errors.append("[X] Getting Started page not found")
        else:
            checks_passed.append("[C] Getting Started page found")

        if not _check_page_is_child_of(getting_started, workspace_navigation_guide):
            errors.append("[X] Workspace Navigation Guide page is not a child of Getting Started page")
        else:
            checks_passed.append("[C] Workspace Navigation Guide page is a child of Getting Started page")

        # 3. Validate 'Workspace Navigation Guide' page is marked as favorite
        if not workspace_navigation_guide.get("isFavorite"):
            errors.append("[X] Workspace Navigation Guide page is not marked as favorite")
        else:
            checks_passed.append("[C] Workspace Navigation Guide page is marked as favorite")

        # 4. Validate 'Workspace Navigation Guide' page contains updated content with navigation tips, organization best practices, collaboration guidelines, workspace tour with bulleted lists, policy callouts, and bookmark checklist
        required_content = [
            "navigation tips",
            "organization best practices",
            "collaboration guidelines",
            "workspace tour",
        ]

        guide_id = workspace_navigation_guide.get("_id")

        for content in required_content:
            success, error = _validate_pages_contain_text(
                final_state_backend, [guide_id], content
            )
            if not success:
                errors.append(f"[X] Workspace Navigation Guide page missing content: {content}")
            else:
                checks_passed.append(f"[C] Workspace Navigation Guide page has content: {content}")

        # Validate page contains to-do blocks
        guide_blocks = _get_blocks_for_page(final_state_backend, guide_id)
        contains_todo = False
        for block in guide_blocks:
            if block.get("type") == "todo":
                contains_todo = True
                break
        if not contains_todo:
            errors.append("[X] Workspace Navigation Guide page does not contain to-do blocks")
        else:
            checks_passed.append("[C] Workspace Navigation Guide page does contains to-do blocks")

        # 5. Validate original 'Onboarding Guide' page remains unchanged
        onboarding_guide = _find_page_by_title(final_state_backend, "Onboarding Guide")
        if not onboarding_guide:
            errors.append("[X] Onboarding Guide page not found")
        else:
            checks_passed.append("[C] Onboarding Guide page found")

        # Check that onboarding guide still has its original content by checking for key phrases
        onboarding_id = onboarding_guide.get("_id")
        onboarding_blocks = _get_blocks_for_page(final_state_backend, onboarding_id)
        if len(onboarding_blocks) == 0:
            errors.append("[X] Onboarding Guide page appears to have been cleared")
        else:
            checks_passed.append("[C] Onboarding Guide page appears to have been cleared")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

    # -----------------------------------------------------------------------------
    # Task: project-structure-copy
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_project_structure_copy(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate project structure copy."""
    errors: list[str] = []
    checks_passed: list[str] = []

    try:
        logger.info(f"Backend type in project_structure_copy: {type(final_state_backend).__name__}")

        # Check if the new page exists
        roadmap_pages = _find_pages_by_title(final_state_backend, "2025")
        logger.info(f"Pages with '2025' in title: {[p.get('title') for p in roadmap_pages]}")
    
        # 1. Validate new 'Project Roadmap - 2025 Edition' page exists with rocket icon
        # Debug: Check all matching pages
        # all_roadmap_pages = _find_pages_by_title(final_state_backend, "Project Roadmap - 2025 Edition")
        # if len(all_roadmap_pages) > 1:
        #     return 0.0, f"Multiple roadmap pages found: {[(p.get('_id'), p.get('parentId')) for p in all_roadmap_pages]}"

        project_roadmap_2025 = _find_page_by_title(final_state_backend, "Project Roadmap - 2025 Edition")
        if not project_roadmap_2025:
            errors.append("[X] Project Roadmap - 2025 Edition page not found")
        else:
            checks_passed.append("[C] Project Roadmap - 2025 Edition page found")

        # 2. Validate new 'Project Roadmap - 2025 Edition' page is a child of 'Project Documentation' page
        project_documentation = _find_page_by_title(final_state_backend, "Project Documentation")
        if not project_documentation:
            errors.append("[X] Project Documentation page not found")
        else:
            checks_passed.append("[C] Project Documentation page found")

        # Debug the parent-child relationship
        roadmap_parent_id = project_roadmap_2025.get("parentId")
        doc_id = project_documentation.get("_id")
        if not _check_page_is_child_of(project_documentation, project_roadmap_2025):
            errors.append(f"[X] Parent check failed: roadmap.parentId='{roadmap_parent_id}' vs doc._id='{doc_id}' (match={roadmap_parent_id == doc_id})")
        else:
            checks_passed.append(f"[C] Parent check succeeded: roadmap.parentId='{roadmap_parent_id}' vs doc._id='{doc_id}' (match={roadmap_parent_id == doc_id})")

        # 3. Validate new 'Project Roadmap - 2025 Edition' page is marked as favorite
        if not project_roadmap_2025.get("isFavorite"):
            errors.append("[X] Project Roadmap - 2025 Edition page is not marked as favorite")
        else:
            checks_passed.append("[C] Project Roadmap - 2025 Edition page is marked as favorite")

        # 4. Validate new 'Project Roadmap - 2025 Edition' page contains updated content with vision heading, quarterly goals numbered list, key milestones bulleted list, and a quote block with team motto
        required_blocks = [
            "heading1",
            "numberedList",
            "bulletedList",
            "quote"
        ]

        roadmap_id = project_roadmap_2025.get("_id")
        page_blocks = _get_blocks_for_page(final_state_backend, roadmap_id)

        # Find unique block types present on the page
        found_block_types = set()
        for block in page_blocks:
            block_type = block.get("type")
            if block_type in required_blocks:
                found_block_types.add(block_type)

        # Check if all required block types are present
        missing_blocks = [block for block in required_blocks if block not in found_block_types]
        if missing_blocks:
            errors.append(f"[X] Project Roadmap - 2025 Edition page missing blocks: {missing_blocks}")
        else:
            checks_passed.append(f"[C] Project Roadmap - 2025 Edition page has blocks: {missing_blocks}")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

    # -----------------------------------------------------------------------------
    # Task: project-task-analysis
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_project_task_analysis(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate project task analysis."""
    errors: list[str] = []
    checks_passed: list[str] = []

    
    
    # 1. Verify 'Project Task Analysis' page exists as child of 'Project Roadmap'
    try:
        project_roadmap = _find_page_by_title(final_state_backend, "Project Roadmap")
        if not project_roadmap:
            errors.append("[X] Project Roadmap page not found")
        else:
            checks_passed.append("[C] Project Roadmap page found")
    
        task_analysis = _find_page_by_title(final_state_backend, "Project Task Analysis")
        if not task_analysis:
            errors.append("[X] Project Task Analysis page not found")
        else:
            checks_passed.append("[C] Project Task Analysis page found")
    
        if not _check_page_is_child_of(project_roadmap, task_analysis):
            errors.append("[X] Project Task Analysis is not a child of Project Roadmap")
        else:
            checks_passed.append("[C] Project Task Analysis is a child of Project Roadmap")
    
        # 2. Get Q1 and Q2 Goals pages to count todos
        q1_goals = _find_page_by_title_pattern_and_parent(final_state_backend, "Q1 Goals", project_roadmap.get("_id"))
        q2_goals = _find_page_by_title_pattern_and_parent(final_state_backend, "Q2 Goals", project_roadmap.get("_id"))
    
        if not q1_goals:
            errors.append("[X] Q1 Goals page not found as child of Project Roadmap")
        else:
            checks_passed.append("[C] Q1 Goals page found as child of Project Roadmap")
        if not q2_goals:
            errors.append("[X] Q2 Goals page not found as child of Project Roadmap")
        else:
            checks_passed.append("[C] Q2 Goals page found as child of Project Roadmap")
    
        # Count todos in Q1 and Q2 pages
        q1_blocks = _get_blocks_for_page(final_state_backend, q1_goals.get("_id"))
        q2_blocks = _get_blocks_for_page(final_state_backend, q2_goals.get("_id"))
    
        q1_todos = [b for b in q1_blocks if b.get("type") == "todo"]
        q2_todos = [b for b in q2_blocks if b.get("type") == "todo"]
    
        q1_checked = [b for b in q1_todos if b.get("properties", {}).get("checked")]
        q1_unchecked = [b for b in q1_todos if not b.get("properties", {}).get("checked")]
    
        q2_checked = [b for b in q2_todos if b.get("properties", {}).get("checked")]
        q2_unchecked = [b for b in q2_todos if not b.get("properties", {}).get("checked")]
    
        total_todos = len(q1_todos) + len(q2_todos)
        q1_completed = len(q1_checked)
        q2_completed = len(q2_checked)
    
        # Calculate expected percentages
        q1_percentage = round((q1_completed / len(q1_todos) * 100) if len(q1_todos) > 0 else 0)
        q2_percentage = round((q2_completed / len(q2_todos) * 100) if len(q2_todos) > 0 else 0)
    
        # 3. Get blocks from Project Task Analysis page
        analysis_blocks = _get_blocks_for_page(final_state_backend, task_analysis.get("_id"))
    
        if len(analysis_blocks) < 8:  # Minimum expected blocks
            errors.append(f"[X] Project Task Analysis page has too few blocks ({len(analysis_blocks)})")
        else:
            checks_passed.append(f"[C] Project Task Analysis page has too few blocks ({len(analysis_blocks)})")
    
        # 4. Validate block structure and order
        block_idx = 0
    
        # Check heading1: '📊 Task Completion Analysis'
        if block_idx >= len(analysis_blocks):
            errors.append("[X] Missing heading1 block")
        else:
            checks_passed.append("[C] has heading1 block")
        if analysis_blocks[block_idx].get("type") != "heading1":
            errors.append(f"[X] Block {block_idx} should be heading1, got {analysis_blocks[block_idx].get('type')}")
        else:
            checks_passed.append(f"[C] Block {block_idx} should be heading1, got {analysis_blocks[block_idx].get('type')}")
        if "task completion analysis" not in analysis_blocks[block_idx].get("content", "").lower():
            errors.append("[X] heading1 should contain 'Task Completion Analysis'")
        else:
            checks_passed.append("[C] heading1 should contain 'Task Completion Analysis'")
        block_idx += 1
    
        # Check heading2: '📈 Overall Statistics'
        if block_idx >= len(analysis_blocks):
            errors.append("[X] Missing heading2 block")
        else:
            checks_passed.append("[C] has heading2 block")
        if analysis_blocks[block_idx].get("type") != "heading2":
            errors.append(f"[X] Block {block_idx} should be heading2, got {analysis_blocks[block_idx].get('type')}")
        else:
            checks_passed.append(f"[C] Block {block_idx} should be heading2, got {analysis_blocks[block_idx].get('type')}")
        if "overall statistics" not in analysis_blocks[block_idx].get("content", "").lower():
            errors.append("[X] heading2 should contain 'Overall Statistics'")
        else:
            checks_passed.append("[C] heading2 should contain 'Overall Statistics'")
        block_idx += 1
    
        # Check callout block (blue background, 📊 icon)
        if block_idx >= len(analysis_blocks):
            errors.append("[X] Missing callout block")
        else:
            checks_passed.append("[C] has callout block")
        callout_block = analysis_blocks[block_idx]
        if callout_block.get("type") != "callout":
            errors.append(f"[X] Block {block_idx} should be callout, got {callout_block.get('type')}")
        else:
            checks_passed.append(f"[C] Block {block_idx} should be callout, got {callout_block.get('type')}")
    
        callout_props = callout_block.get("properties", {})
        if callout_props.get("backgroundColor") != "blue":
            errors.append(f"[X] Callout should have blue background, got {callout_props.get('backgroundColor')}")
        else:
            checks_passed.append(f"[C] Callout should have blue background, got {callout_props.get('backgroundColor')}")
        if callout_props.get("icon") != "📊":
            errors.append(f"[X] Callout should have 📊 icon, got {callout_props.get('icon')}")
        else:
            checks_passed.append(f"[C] Callout should have 📊 icon, got {callout_props.get('icon')}")
    
        # Callout should contain "Quarterly Overview" and total count
        callout_content = callout_block.get("content", "").lower()
        if "quarterly overview" not in callout_content:
            errors.append("[X] Callout should contain 'Quarterly Overview'")
        else:
            checks_passed.append("[C] Callout should contain 'Quarterly Overview'")
        if f"total tasks across q1 and q2: {total_todos}" not in callout_content:
            errors.append(f"[X] Callout should contain 'Total tasks across Q1 and Q2: {total_todos}'")
        else:
            checks_passed.append(f"[C] Callout should contain 'Total tasks across Q1 and Q2: {total_todos}'")
        block_idx += 1
    
        # Check Q1 section
        # heading3: '🎯 Q1 Progress'
        if block_idx >= len(analysis_blocks):
            errors.append("[X] Missing Q1 heading3 block")
        else:
            checks_passed.append("[C] has Q1 heading3 block")
        if analysis_blocks[block_idx].get("type") != "heading3":
            errors.append(f"[X] Block {block_idx} should be heading3 for Q1")
        else:
            checks_passed.append(f"[C] Block {block_idx} should be heading3 for Q1")
        if "q1 progress" not in analysis_blocks[block_idx].get("content", "").lower():
            errors.append("[X] heading3 should contain 'Q1 Progress'")
        else:
            checks_passed.append("[C] heading3 should contain 'Q1 Progress'")
        block_idx += 1
    
        # paragraph with completion stats
        if block_idx >= len(analysis_blocks):
            errors.append("[X] Missing Q1 statistics paragraph")
        else:
            checks_passed.append("[C] has Q1 statistics paragraph")
        q1_para = analysis_blocks[block_idx]
        if q1_para.get("type") != "paragraph":
            errors.append(f"[X] Block {block_idx} should be paragraph with Q1 stats")
        else:
            checks_passed.append(f"[C] Block {block_idx} should be paragraph with Q1 stats")
    
        q1_para_content = q1_para.get("content", "").lower()
        if f"completed: {q1_completed}" not in q1_para_content:
            errors.append(f"[X] Q1 paragraph should show 'Completed: {q1_completed}'")
        else:
            checks_passed.append(f"[C] Q1 paragraph should show 'Completed: {q1_completed}'")
        if f"({q1_percentage}%)" not in q1_para_content:
            errors.append(f"[X] Q1 paragraph should show '({q1_percentage}%)'")
        else:
            checks_passed.append(f"[C] Q1 paragraph should show '({q1_percentage}%)'")
        block_idx += 1
    
        # numbered list with unchecked Q1 todos
        q1_list_items = []
        while block_idx < len(analysis_blocks) and analysis_blocks[block_idx].get("type") == "numberedList":
            q1_list_items.append(analysis_blocks[block_idx])
            block_idx += 1
    
        if len(q1_list_items) != len(q1_unchecked):
            errors.append(f"[X] Expected {len(q1_unchecked)} numbered list items for Q1 unchecked todos, found {len(q1_list_items)}")
        else:
            checks_passed.append(f"[C] Expected {len(q1_unchecked)} numbered list items for Q1 unchecked todos, found {len(q1_list_items)}")
    
        # Verify list items contain unchecked todo texts
        q1_unchecked_texts = [b.get("content", "").lower() for b in q1_unchecked]
        for list_item in q1_list_items:
            list_content = list_item.get("content", "").lower()
            # Check if this list item matches any unchecked todo
            found_match = False
            for todo_text in q1_unchecked_texts:
                if todo_text and todo_text in list_content:
                    found_match = True
                    break
            if not found_match:
                errors.append(f"[X] Q1 numbered list item '{list_item.get('content')}' doesn't match any unchecked todo")
            else:
                checks_passed.append(f"[C] Q1 numbered list item '{list_item.get('content')}' doesn't match any unchecked todo")
    
        # Check Q2 section
        # heading3: '🎯 Q2 Progress'
        if block_idx >= len(analysis_blocks):
            errors.append("[X] Missing Q2 heading3 block")
        else:
            checks_passed.append("[C] has Q2 heading3 block")
        if analysis_blocks[block_idx].get("type") != "heading3":
            errors.append(f"[X] Block {block_idx} should be heading3 for Q2")
        else:
            checks_passed.append(f"[C] Block {block_idx} should be heading3 for Q2")
        if "q2 progress" not in analysis_blocks[block_idx].get("content", "").lower():
            errors.append("[X] heading3 should contain 'Q2 Progress'")
        else:
            checks_passed.append("[C] heading3 should contain 'Q2 Progress'")
        block_idx += 1
    
        # paragraph with completion stats
        if block_idx >= len(analysis_blocks):
            errors.append("[X] Missing Q2 statistics paragraph")
        else:
            checks_passed.append("[C] has Q2 statistics paragraph")
        q2_para = analysis_blocks[block_idx]
        if q2_para.get("type") != "paragraph":
            errors.append(f"[X] Block {block_idx} should be paragraph with Q2 stats")
        else:
            checks_passed.append(f"[C] Block {block_idx} should be paragraph with Q2 stats")
    
        q2_para_content = q2_para.get("content", "").lower()
        if f"completed: {q2_completed}" not in q2_para_content:
            errors.append(f"[X] Q2 paragraph should show 'Completed: {q2_completed}'")
        else:
            checks_passed.append(f"[C] Q2 paragraph should show 'Completed: {q2_completed}'")
        if f"({q2_percentage}%)" not in q2_para_content:
            errors.append(f"[X] Q2 paragraph should show '({q2_percentage}%)'")
        else:
            checks_passed.append(f"[C] Q2 paragraph should show '({q2_percentage}%)'")
        block_idx += 1
    
        # numbered list with unchecked Q2 todos
        q2_list_items = []
        while block_idx < len(analysis_blocks) and analysis_blocks[block_idx].get("type") == "numberedList":
            q2_list_items.append(analysis_blocks[block_idx])
            block_idx += 1
    
        if len(q2_list_items) != len(q2_unchecked):
            errors.append(f"[X] Expected {len(q2_unchecked)} numbered list items for Q2 unchecked todos, found {len(q2_list_items)}")
        else:
            checks_passed.append(f"[C] Expected {len(q2_unchecked)} numbered list items for Q2 unchecked todos, found {len(q2_list_items)}")
    
        # Verify list items contain unchecked todo texts
        q2_unchecked_texts = [b.get("content", "").lower() for b in q2_unchecked]
        for list_item in q2_list_items:
            list_content = list_item.get("content", "").lower()
            # Check if this list item matches any unchecked todo
            found_match = False
            for todo_text in q2_unchecked_texts:
                if todo_text and todo_text in list_content:
                    found_match = True
                    break
            if not found_match:
                errors.append(f"[X] Q2 numbered list item '{list_item.get('content')}' doesn't match any unchecked todo")
            else:
                checks_passed.append(f"[C] Q2 numbered list item '{list_item.get('content')}' doesn't match any unchecked todo")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

    # -----------------------------------------------------------------------------
    # Task: weekly-standup-time-sensitive
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_weekly_standup_time_sensitive(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate weekly standup time-sensitive items task.
    
    Success criteria:
    1. The heading_3 '⏰ Time-Sensitive Items' appears exactly after block-9-8 and before 'Blockers' heading
    2. Three todo blocks with exact specified text and emojis exist under the new heading
    3. All new todos are unchecked
    4. The progress paragraph at the end shows correct counts (2 checked, 8 total, 25.0%)
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    
    # 1. Find Weekly Standup Template page (page-9)
    try:
        standup_page = _find_page_by_title(final_state_backend, "Weekly Standup Template")
        if not standup_page:
            errors.append("[X] Weekly Standup Template page not found")
        else:
            checks_passed.append("[C] Weekly Standup Template page found")
    
        page_id = standup_page.get("_id")
        page_blocks = _get_blocks_for_page(final_state_backend, page_id)
    
        if not page_blocks:
            errors.append("[X] No blocks found on Weekly Standup Template page")
        else:
            checks_passed.append("[C] blocks found on Weekly Standup Template page")
    
        # Sort blocks by order to ensure correct sequence
        page_blocks_sorted = sorted(page_blocks, key=lambda b: b.get("order", 0))
    
        # 2. Find block-9-8 (Write documentation for new API) and Blockers heading positions
        block_9_8_idx = None
        blockers_heading_idx = None
        time_sensitive_heading_idx = None
    
        for idx, block in enumerate(page_blocks_sorted):
            block_id = block.get("_id", "")
            content = block.get("content", "").lower()
            block_type = block.get("type", "")
        
            if block_id == "block-9-8" or "write documentation for new api" in content:
                block_9_8_idx = idx
        
            if block_type in ["heading2", "heading3"] and "blockers" in content:
                blockers_heading_idx = idx
        
            if block_type == "heading3" and "time-sensitive items" in content:
                time_sensitive_heading_idx = idx
    
        if block_9_8_idx is None:
            errors.append("[X] block-9-8 ('Write documentation for new API' todo) not found")
        else:
            checks_passed.append("[C] block-9-8 ('Write documentation for new API' todo) found")
    
        if blockers_heading_idx is None:
            errors.append("[X] 'Blockers' heading not found")
        else:
            checks_passed.append("[C] 'Blockers' heading found")
    
        # 3. Verify heading_3 '⏰ Time-Sensitive Items' exists between block-9-8 and Blockers
        if time_sensitive_heading_idx is None:
            errors.append("[X] heading_3 '⏰ Time-Sensitive Items' not found")
        else:
            checks_passed.append("[C] heading_3 '⏰ Time-Sensitive Items' found")
    
        if time_sensitive_heading_idx <= block_9_8_idx:
            errors.append(f"[X] '⏰ Time-Sensitive Items' heading must appear AFTER block-9-8 (found at index {time_sensitive_heading_idx}, block-9-8 at {block_9_8_idx})")
        else:
            checks_passed.append(f"[C] '⏰ Time-Sensitive Items' heading must appear AFTER block-9-8 (found at index {time_sensitive_heading_idx}, block-9-8 at {block_9_8_idx})")
    
        if time_sensitive_heading_idx >= blockers_heading_idx:
            errors.append(f"[X] '⏰ Time-Sensitive Items' heading must appear BEFORE 'Blockers' heading (found at index {time_sensitive_heading_idx}, Blockers at {blockers_heading_idx})")
        else:
            checks_passed.append(f"[C] '⏰ Time-Sensitive Items' heading must appear BEFORE 'Blockers' heading (found at index {time_sensitive_heading_idx}, Blockers at {blockers_heading_idx})")
    
        # 4. Verify the three required todo blocks exist after the heading and before Blockers
        required_todos = [
            "🚨 Complete security audit by Friday EOD",
            "📊 Present Q1 metrics to stakeholders",
            "🔄 Merge critical bug fix PR #1234"
        ]
    
        # Look for todos between time_sensitive_heading_idx and blockers_heading_idx
        found_todos = []
        for idx in range(time_sensitive_heading_idx + 1, blockers_heading_idx):
            block = page_blocks_sorted[idx]
            if block.get("type") == "todo":
                found_todos.append(block)
    
        if len(found_todos) < 3:
            errors.append(f"[X] Expected 3 todo blocks under '⏰ Time-Sensitive Items', found {len(found_todos)}")
        else:
            checks_passed.append(f"[C] Found 3 todo blocks under '⏰ Time-Sensitive Items' as expected")
    
        # Check that required todos are present with exact text
        found_todo_texts = [b.get("content", "") for b in found_todos]
    
        for required_todo in required_todos:
            found = False
            for found_text in found_todo_texts:
                if required_todo.lower() in found_text.lower() or found_text.lower() in required_todo.lower():
                    found = True
                    break
            if not found:
                errors.append(f"[X] Required todo not found: '{required_todo}'")
            else:
                checks_passed.append(f"[C] Required todo found: '{required_todo}'")
    
        # 5. Verify all new todos are unchecked
        for todo_block in found_todos:
            properties = todo_block.get("properties", {})
            if properties.get("checked", False):
                errors.append(f"[X] New todo block should be unchecked: '{todo_block.get('content')}'")
            else:
                checks_passed.append(f"[C] New todo block should be unchecked: '{todo_block.get('content')}'")
    
        # 6. Count all todos on the page and verify progress paragraph
        all_page_todos = [b for b in page_blocks_sorted if b.get("type") == "todo"]
        total_todos = len(all_page_todos)
        checked_todos = sum(1 for b in all_page_todos if b.get("properties", {}).get("checked", False))
    
        # Expected: 2 checked (original), 8 total (5 original + 3 new)
        expected_checked = 2
        expected_total = 8
        expected_percentage = 25.0
    
        if total_todos != expected_total:
            errors.append(f"[X] Expected {expected_total} total todos, found {total_todos}")
        else:
            checks_passed.append(f"[C] Expected {expected_total} total todos, found {total_todos}")
    
        if checked_todos != expected_checked:
            errors.append(f"[X] Expected {expected_checked} checked todos, found {checked_todos}")
        else:
            checks_passed.append(f"[C] Expected {expected_checked} checked todos, found {checked_todos}")
    
        # 7. Verify progress paragraph at the end of the page
        last_block = page_blocks_sorted[-1]
        if last_block.get("type") != "paragraph":
            errors.append(f"[X] Last block should be a paragraph with progress update, found type '{last_block.get('type')}'")
        else:
            checks_passed.append(f"[C] Last block should be a paragraph with progress update, found type '{last_block.get('type')}'")
    
        progress_content = last_block.get("content", "")
        expected_progress_text = f"Progress Update: {expected_checked} of {expected_total} tasks completed ({expected_percentage}%)"
    
        # Flexible matching - check key components are present
        progress_lower = progress_content.lower()
        if "progress update" not in progress_lower:
            errors.append(f"[X] Progress paragraph should contain 'Progress Update', found: '{progress_content}'")
        else:
            checks_passed.append(f"[C] Progress paragraph should contain 'Progress Update', found: '{progress_content}'")
    
        if str(expected_checked) not in progress_content:
            errors.append(f"[X] Progress paragraph should show {expected_checked} checked todos, found: '{progress_content}'")
        else:
            checks_passed.append(f"[C] Progress paragraph should show {expected_checked} checked todos, found: '{progress_content}'")
    
        if str(expected_total) not in progress_content:
            errors.append(f"[X] Progress paragraph should show {expected_total} total todos, found: '{progress_content}'")
        else:
            checks_passed.append(f"[C] Progress paragraph should show {expected_total} total todos, found: '{progress_content}'")
    
        # Check percentage (allow flexible format like 25.0%, 25%, 25.0)
        if "25" not in progress_content:
            errors.append(f"[X] Progress paragraph should show 25% or 25.0%, found: '{progress_content}'")
        else:
            checks_passed.append(f"[C] Progress paragraph should show 25% or 25.0%, found: '{progress_content}'")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

    # -----------------------------------------------------------------------------
    # Task: code-examples-toc
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_code_examples_toc(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate sophisticated table of contents system on Code Examples Repository page.
    
    Success criteria:
    1. Blue callout with TOC appears after main heading_1 but before other content
    2. Numbered list contains all heading_2 blocks in order
    3. Each code block has a gray paragraph above it with correct numbering
    4. Green callout at page end contains link to Engineering Wiki
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    
    # 1. Find 'Code Examples Repository' page
    try:
        code_examples_page = _find_page_by_title(final_state_backend, "Code Examples Repository")
        if not code_examples_page:
            errors.append("[X] Code Examples Repository page not found")
        else:
            checks_passed.append("[C] Code Examples Repository page found")
    
        page_id = code_examples_page.get("_id")
        page_blocks = _get_blocks_for_page(final_state_backend, page_id)
    
        if not page_blocks:
            errors.append("[X] No blocks found on Code Examples Repository page")
        else:
            checks_passed.append("[C] blocks found on Code Examples Repository page")
    
        # Sort blocks by order to ensure correct sequence
        page_blocks_sorted = sorted(page_blocks, key=lambda b: b.get("order", 0))
    
        # 2. Find all heading blocks and count them
        heading_blocks = [b for b in page_blocks_sorted if b.get("type") in ["heading1", "heading2", "heading3"]]
        heading_2_blocks = [b for b in page_blocks_sorted if b.get("type") == "heading2"]
    
        if not heading_blocks:
            errors.append("[X] No heading blocks found on the page")
        else:
            checks_passed.append("[C] heading blocks found on the page")
    
        # 3. Find the main heading_1 (should be first)
        main_heading_idx = None
        for idx, block in enumerate(page_blocks_sorted):
            if block.get("type") == "heading1":
                main_heading_idx = idx
                break
    
        if main_heading_idx is None:
            errors.append("[X] Main heading_1 not found on the page")
        else:
            checks_passed.append("[C] Main heading_1 found on the page")
    
        # 4. Verify blue callout with TOC appears after main heading_1 but before other content
        toc_callout_idx = None
        for idx, block in enumerate(page_blocks_sorted):
            if block.get("type") == "callout":
                props = block.get("properties", {})
                content = block.get("content", "").lower()
                if props.get("backgroundColor") == "blue_background" or props.get("backgroundColor") == "blue":
                    if props.get("icon") == "📑":
                        if "interactive table of contents" in content or "table of contents" in content:
                            toc_callout_idx = idx
                            break
    
        if toc_callout_idx is None:
            errors.append("[X] Blue callout with '📑' icon and 'Interactive Table of Contents' not found")
        else:
            checks_passed.append("[C] Blue callout with '📑' icon and 'Interactive Table of Contents' found")
    
        if toc_callout_idx <= main_heading_idx:
            errors.append(f"[X] TOC callout (idx {toc_callout_idx}) must appear AFTER main heading_1 (idx {main_heading_idx})")
        else:
            checks_passed.append(f"[C] TOC callout (idx {toc_callout_idx}) must appear AFTER main heading_1 (idx {main_heading_idx})")
    
        # 5. Verify 'Jump to section:' paragraph and numbered list follows the callout
        jump_to_section_idx = None
        for idx in range(toc_callout_idx + 1, min(toc_callout_idx + 3, len(page_blocks_sorted))):
            block = page_blocks_sorted[idx]
            if block.get("type") == "paragraph":
                if "jump to section" in block.get("content", "").lower():
                    jump_to_section_idx = idx
                    break
    
        if jump_to_section_idx is None:
            errors.append("[X] Paragraph with 'Jump to section:' not found after TOC callout")
        else:
            checks_passed.append("[C] Paragraph with 'Jump to section:' found after TOC callout")
    
        # 6. Verify numbered list with heading_2 entries follows
        numbered_list_items = []
        for idx in range(jump_to_section_idx + 1, len(page_blocks_sorted)):
            block = page_blocks_sorted[idx]
            if block.get("type") == "numberedList":
                numbered_list_items.append(block)
            elif block.get("type") == "divider":
                # Stop at divider
                break
            elif block.get("type") not in ["numberedList"]:
                # If we hit something else before divider, check if we have items
                break
    
        # Get original heading_2 blocks (excluding any that might be in the TOC section)
        # Original heading_2s are those that existed before the TOC was added
        original_heading_2_texts = []
        for h2 in heading_2_blocks:
            h2_content = h2.get("content", "")
            # Skip if this is part of TOC structure
            if "jump to section" not in h2_content.lower() and "table of contents" not in h2_content.lower():
                original_heading_2_texts.append(h2_content)
    
        if len(numbered_list_items) == 0:
            errors.append("[X] No numbered list items found for table of contents")
        else:
            checks_passed.append("[C] numbered list items found for table of contents")
    
        # Verify numbered list contains heading_2 texts
        list_texts = [item.get("content", "").lower() for item in numbered_list_items]
        for h2_text in original_heading_2_texts:
            found = False
            h2_text_lower = h2_text.lower()
            for list_text in list_texts:
                if h2_text_lower in list_text or list_text in h2_text_lower:
                    found = True
                    break
            if not found:
                # Allow partial match
                pass  # Relaxed validation - just check count matches
    
        # 7. Verify divider exists after TOC
        divider_after_toc = False
        for idx in range(jump_to_section_idx + 1, len(page_blocks_sorted)):
            block = page_blocks_sorted[idx]
            if block.get("type") == "divider":
                divider_after_toc = True
                break
            # Don't go too far
            if idx > jump_to_section_idx + len(numbered_list_items) + 5:
                break
    
        if not divider_after_toc:
            errors.append("[X] Divider not found after table of contents")
        else:
            checks_passed.append("[C] Divider found after table of contents")
    
        # 8. Find all code blocks and verify gray paragraphs above them
        code_blocks = [b for b in page_blocks_sorted if b.get("type") == "code"]
        total_code_blocks = len(code_blocks)
    
        if total_code_blocks == 0:
            errors.append("[X] No code blocks found on the page")
        else:
            checks_passed.append("[C] code blocks found on the page")
    
        # For each code block, check if there's a paragraph above with correct snippet numbering
        code_snippet_labels_found = 0
        for code_block in code_blocks:
            code_block_idx = page_blocks_sorted.index(code_block)
            if code_block_idx > 0:
                prev_block = page_blocks_sorted[code_block_idx - 1]
                if prev_block.get("type") == "paragraph":
                    content = prev_block.get("content", "").lower()
                    props = prev_block.get("properties", {})
                    # Check for code snippet label pattern
                    if "💻" in prev_block.get("content", "") or "code snippet" in content:
                        if str(total_code_blocks) in prev_block.get("content", ""):
                            code_snippet_labels_found += 1
                        elif f"of {total_code_blocks}" in content:
                            code_snippet_labels_found += 1
                        else:
                            # More lenient - just check for the pattern
                            if "snippet" in content and "of" in content:
                                code_snippet_labels_found += 1
    
        if code_snippet_labels_found < total_code_blocks:
            errors.append(f"[X] Expected {total_code_blocks} code snippet labels, found {code_snippet_labels_found}")
        else:
            checks_passed.append(f"[C] Expected {total_code_blocks} code snippet labels, found {code_snippet_labels_found}")
    
        # 9. Verify green callout at the end with Engineering Wiki link
        last_blocks = page_blocks_sorted[-5:] if len(page_blocks_sorted) >= 5 else page_blocks_sorted
        green_callout_found = False
        engineering_wiki_link_found = False
    
        for block in reversed(last_blocks):
            if block.get("type") == "callout":
                props = block.get("properties", {})
                content = block.get("content", "").lower()
                if props.get("backgroundColor") == "green_background" or props.get("backgroundColor") == "green":
                    if props.get("icon") == "✨":
                        green_callout_found = True
                        # Check for Engineering Wiki mention
                        if "engineering wiki" in content:
                            engineering_wiki_link_found = True
                            break
    
        if not green_callout_found:
            errors.append("[X] Green callout with '✨' icon not found at the end of the page")
        else:
            checks_passed.append("[C] Green callout with '✨' icon found at the end of the page")
    
        if not engineering_wiki_link_found:
            errors.append("[X] Green callout does not contain reference to 'Engineering Wiki'")
        else:
            checks_passed.append("[C] Green callout does contains reference to 'Engineering Wiki'")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

    # -----------------------------------------------------------------------------
    # Task: prd-section-summaries
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_prd_section_summaries(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate PRD section summaries task.
    
    Success criteria:
    1. Must identify all Part 3 subsections in the Product Requirements Document
    2. Each summary box must be inserted at correct position (after Part 3 content, before next heading_2)
    3. Summary box structure: divider -> callout (purple_background, 📊 icon)
    4. Callout contains: 'Section Summary' heading, paragraph with bullet count, todo with section name
    5. Must count bulletedList items per section correctly
    6. Todo must reference the parent section name (heading_2 text)
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    
    # 1. Find 'Product Requirements Document' page
    try:
        prd_page = _find_page_by_title(final_state_backend, "Comprehensive Product Requirements Document")
        if not prd_page:
            errors.append("[X] Comprehensive Product Requirements Document page not found")
        else:
            checks_passed.append("[C] Comprehensive Product Requirements Document page found")
    
        page_id = prd_page.get("_id")
        page_blocks = _get_blocks_for_page(final_state_backend, page_id)
    
        if not page_blocks:
            errors.append("[X] No blocks found on Comprehensive Product Requirements Document page")
        else:
            checks_passed.append("[C] blocks found on Comprehensive Product Requirements Document page")
    
        # Sort blocks by order to ensure correct sequence
        page_blocks_sorted = sorted(page_blocks, key=lambda b: b.get("order", 0))
    
        # 2. Identify sections: Find all heading_2 blocks (major sections) and Part 3 heading_3 blocks
        sections = []  # List of (section_name, heading_2_idx, part_3_idx, next_section_idx)
    
        heading_2_indices = []
        part_3_indices = []
    
        for idx, block in enumerate(page_blocks_sorted):
            block_type = block.get("type", "")
            content = block.get("content", "")
        
            if block_type == "heading2":
                heading_2_indices.append((idx, content))
            elif block_type == "heading3" and "part 3" in content.lower():
                part_3_indices.append(idx)
    
        if len(heading_2_indices) == 0:
            errors.append("[X] No heading_2 (section headers) found in the document")
        else:
            checks_passed.append("[C] heading_2 (section headers) found in the document")
    
        if len(part_3_indices) == 0:
            errors.append("[X] No 'Part 3' heading_3 blocks found in the document")
        else:
            checks_passed.append("[C] 'Part 3' heading_3 blocks found in the document")
    
        # 3. Map each Part 3 to its parent section and determine boundaries
        for part_3_idx in part_3_indices:
            # Find the parent heading_2 (the last heading_2 before this Part 3)
            parent_section = None
            parent_section_idx = None
            for h2_idx, h2_content in heading_2_indices:
                if h2_idx < part_3_idx:
                    parent_section = h2_content
                    parent_section_idx = h2_idx
                else:
                    break
        
            if parent_section is None:
                continue
        
            # Find the next heading_2 after this Part 3 (end boundary for summary insertion)
            next_section_idx = len(page_blocks_sorted)  # Default to end of document
            for h2_idx, _ in heading_2_indices:
                if h2_idx > part_3_idx:
                    next_section_idx = h2_idx
                    break
        
            sections.append({
                "section_name": parent_section,
                "section_start_idx": parent_section_idx,
                "part_3_idx": part_3_idx,
                "next_section_idx": next_section_idx
            })
    
        if len(sections) == 0:
            errors.append("[X] Could not map Part 3 blocks to parent sections")
        else:
            checks_passed.append("[C] Could map Part 3 blocks to parent sections")
    
        # 4. For each section, validate the summary box was inserted correctly
        validated_sections = 0
        validation_errors = []
    
        for section_info in sections:
            section_name = section_info["section_name"]
            section_start_idx = section_info["section_start_idx"]
            part_3_idx = section_info["part_3_idx"]
            next_section_idx = section_info["next_section_idx"]
        
            # Count bulletedList items in this section (between section_start_idx and next_section_idx)
            bulleted_list_count = 0
            for idx in range(section_start_idx, next_section_idx):
                if idx < len(page_blocks_sorted):
                    block = page_blocks_sorted[idx]
                    if block.get("type") == "bulletedList":
                        bulleted_list_count += 1
        
            # Find the summary box components after Part 3 but before next section
            # We need to find: divider, then callout (purple with 📊)
        
            # First, find where Part 3's content ends (look for the last bulletedList after Part 3 heading)
            part_3_content_end = part_3_idx + 1
            for idx in range(part_3_idx + 1, next_section_idx):
                block = page_blocks_sorted[idx]
                block_type = block.get("type", "")
                # Part 3 content typically includes bulletedList items
                if block_type == "bulletedList":
                    part_3_content_end = idx + 1
                elif block_type in ["heading2", "heading3", "divider"]:
                    # Stop at next heading or divider
                    break
        
            # Look for summary box between part_3_content_end and next_section_idx
            divider_found = False
            callout_found = False
            callout_valid = False
            callout_has_section_summary = False
            callout_has_bullet_count = False
            callout_has_todo = False
        
            for idx in range(part_3_content_end, next_section_idx):
                if idx >= len(page_blocks_sorted):
                    break
                block = page_blocks_sorted[idx]
                block_type = block.get("type", "")
            
                if block_type == "divider":
                    divider_found = True
            
                if block_type == "callout":
                    callout_found = True
                    props = block.get("properties", {})
                    content = block.get("content", "")
                
                    # Check callout properties
                    bg_color = props.get("backgroundColor", "")
                    icon = props.get("icon", "")
                
                    if "purple" in bg_color.lower() and icon == "📊":
                        callout_valid = True
                
                    # Check callout content
                    content_lower = content.lower()
                
                    if "section summary" in content_lower:
                        callout_has_section_summary = True
                
                    # Check for bullet count pattern: "This section contains [X] key points across [Y] parts"
                    # We expect Y = 3 (number of parts)
                    if "key points" in content_lower and "parts" in content_lower:
                        # Try to extract the number
                        if str(bulleted_list_count) in content or "across 3 parts" in content_lower:
                            callout_has_bullet_count = True
                        else:
                            # Be more lenient - just check the pattern exists
                            if "contains" in content_lower and "across" in content_lower:
                                callout_has_bullet_count = True
                
                    # Check for todo with section name reference
                    # Clean section name for comparison (remove emojis and extra whitespace)
                    clean_section_name = section_name.strip()
                    # Remove common emojis
                    for emoji in ["📋", "📝", "📌", "🎯", "📊", "💡", "🔧", "⚙️", "🚀", "✨"]:
                        clean_section_name = clean_section_name.replace(emoji, "").strip()
                
                    if "review completed for" in content_lower:
                        # Check if section name is referenced
                        if clean_section_name.lower() in content_lower:
                            callout_has_todo = True
                        else:
                            # Partial match - check if any significant word from section name is present
                            section_words = [w for w in clean_section_name.lower().split() if len(w) > 3]
                            for word in section_words:
                                if word in content_lower:
                                    callout_has_todo = True
                                    break
        
            # Validate this section's summary box
            section_valid = True
            section_errors = []
        
            if not divider_found:
                section_valid = False
                section_errors.append("missing divider")
        
            if not callout_found:
                section_valid = False
                section_errors.append("missing callout")
            elif not callout_valid:
                section_valid = False
                section_errors.append("callout not purple_background with 📊 icon")
            else:
                if not callout_has_section_summary:
                    section_valid = False
                    section_errors.append("callout missing 'Section Summary' heading")
                if not callout_has_bullet_count:
                    section_valid = False
                    section_errors.append(f"callout missing bullet count (expected ~{bulleted_list_count} key points)")
                if not callout_has_todo:
                    section_valid = False
                    section_errors.append(f"callout missing todo with section name '{clean_section_name}'")
        
            if section_valid:
                validated_sections += 1
            else:
                validation_errors.append(f"Section '{section_name}': {', '.join(section_errors)}")
    
        # 5. Final validation
        total_sections = len(sections)
    
        if validated_sections == 0:
            error_details = "; ".join(validation_errors[:3])  # Show first 3 errors
            errors.append(f"[X] No valid summary boxes found. Errors: {error_details}")
        else:
            checks_passed.append(f"[C] valid summary boxes found. Errors: {error_details}")
    
        if validated_sections < total_sections:
            missing_count = total_sections - validated_sections
            error_details = "; ".join(validation_errors[:2])
            errors.append(f"[X] Only {validated_sections}/{total_sections} sections have valid summary boxes. Issues: {error_details}")
        else:
            checks_passed.append(f"[C] Only {validated_sections}/{total_sections} sections have valid summary boxes. Issues: {error_details}")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

    # -----------------------------------------------------------------------------
    # Task: company-handbook-reorganization-2
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_company_handbook_reorganization_2(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Company Handbook reorganization task.
    
    Success criteria:
    1. 'Work Policies' section now appears before 'Our Values' with all original content intact
    2. New '🏠 Hybrid Work Policy' subsection appears exactly between 'Remote Work' and 'Time Off'
    3. Green callout with lightbulb emoji contains exact specified text
    4. All Benefits items converted from numbered to bulleted lists
    5. New wellness benefit added as last bullet point
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    
    # 1. Find 'Company Handbook' page
    try:
        handbook_page = _find_page_by_title(final_state_backend, "Company Handbook")
        if not handbook_page:
            errors.append("[X] Company Handbook page not found")
        else:
            checks_passed.append("[C] Company Handbook page found")
    
        page_id = handbook_page.get("_id")
        page_blocks = _get_blocks_for_page(final_state_backend, page_id)
    
        if not page_blocks:
            errors.append("[X] No blocks found on Company Handbook page")
        else:
            checks_passed.append("[C] blocks found on Company Handbook page")
    
        # Sort blocks by order
        page_blocks_sorted = sorted(page_blocks, key=lambda b: b.get("order", 0))
    
        # 2. Find the positions of key sections
        work_policies_idx = None
        our_values_idx = None
        remote_work_idx = None
        time_off_idx = None
        hybrid_work_idx = None
        benefits_idx = None
    
        for idx, block in enumerate(page_blocks_sorted):
            block_type = block.get("type", "")
            content = block.get("content", "").lower()
        
            if block_type == "heading2" and "work policies" in content:
                work_policies_idx = idx
            elif block_type == "heading2" and "our values" in content:
                our_values_idx = idx
            elif block_type == "heading3" and "remote work" in content:
                remote_work_idx = idx
            elif block_type == "heading3" and "time off" in content:
                time_off_idx = idx
            elif block_type == "heading3" and "hybrid work" in content:
                hybrid_work_idx = idx
            elif block_type == "heading2" and "benefits" in content:
                benefits_idx = idx
    
        # Validation 1: Work Policies must appear before Our Values
        if work_policies_idx is None:
            errors.append("[X] heading_2 'Work Policies' not found")
        else:
            checks_passed.append("[C] heading_2 'Work Policies' found")
    
        if our_values_idx is None:
            errors.append("[X] heading_2 'Our Values' not found")
        else:
            checks_passed.append("[C] heading_2 'Our Values' found")
    
        if work_policies_idx >= our_values_idx:
            errors.append(f"[X] 'Work Policies' (idx {work_policies_idx}) must appear BEFORE 'Our Values' (idx {our_values_idx})")
        else:
            checks_passed.append(f"[C] 'Work Policies' (idx {work_policies_idx}) must appear BEFORE 'Our Values' (idx {our_values_idx})")
    
        # Validate Work Policies section has Remote Work, Hybrid Work Policy, and Time Off subsections in order
        if remote_work_idx is None:
            errors.append("[X] heading_3 'Remote Work' not found under Work Policies")
        else:
            checks_passed.append("[C] heading_3 'Remote Work' found under Work Policies")
    
        if hybrid_work_idx is None:
            errors.append("[X] heading_3 '🏠 Hybrid Work Policy' not found")
        else:
            checks_passed.append("[C] heading_3 '🏠 Hybrid Work Policy' found")
    
        if time_off_idx is None:
            errors.append("[X] heading_3 'Time Off' not found")
        else:
            checks_passed.append("[C] heading_3 'Time Off' found")
    
        # Verify Remote Work appears before Hybrid Work Policy
        if remote_work_idx >= hybrid_work_idx:
            errors.append(f"[X] 'Remote Work' (idx {remote_work_idx}) must appear BEFORE 'Hybrid Work Policy' (idx {hybrid_work_idx})")
        else:
            checks_passed.append(f"[C] 'Remote Work' (idx {remote_work_idx}) must appear BEFORE 'Hybrid Work Policy' (idx {hybrid_work_idx})")
    
        # Validation 2: Hybrid Work Policy must appear between Remote Work and Time Off
        if hybrid_work_idx >= time_off_idx:
            errors.append(f"[X] 'Hybrid Work Policy' (idx {hybrid_work_idx}) must appear BEFORE 'Time Off' (idx {time_off_idx})")
        else:
            checks_passed.append(f"[C] 'Hybrid Work Policy' (idx {hybrid_work_idx}) must appear BEFORE 'Time Off' (idx {time_off_idx})")
    
        # Validation 3: Check for the new paragraph and green callout after Hybrid Work Policy
        # Look for paragraph with exact text and green callout with 💡 icon
        expected_paragraph = "employees may work from the office 2-3 days per week based on team needs"
        expected_callout_text = "pro tip: coordinate office days with your team for better collaboration!"
    
        paragraph_found = False
        callout_found = False
        callout_valid = False
    
        for idx in range(hybrid_work_idx + 1, time_off_idx):
            block = page_blocks_sorted[idx]
            block_type = block.get("type", "")
            content = block.get("content", "").lower()
        
            if block_type == "paragraph" and expected_paragraph in content:
                paragraph_found = True
        
            if block_type == "callout":
                callout_found = True
                props = block.get("properties", {})
                bg_color = props.get("backgroundColor", "").lower()
                icon = props.get("icon", "")
            
                # Check for green background (could be 'green' or 'green_background')
                if "green" in bg_color and icon == "💡":
                    if expected_callout_text in content:
                        callout_valid = True
    
        if not paragraph_found:
            errors.append(f"[X] Paragraph with text '{expected_paragraph}' not found under Hybrid Work Policy")
        else:
            checks_passed.append(f"[C] Paragraph with text '{expected_paragraph}' found under Hybrid Work Policy")
    
        if not callout_found:
            errors.append("[X] Callout block not found under Hybrid Work Policy")
        else:
            checks_passed.append("[C] Callout block found under Hybrid Work Policy")
    
        if not callout_valid:
            errors.append("[X] Callout block should have green background, 💡 icon, and contain 'Pro tip: Coordinate office days with your team for better collaboration!'")
        else:
            checks_passed.append("[C] Callout block should have green background, 💡 icon, and contain 'Pro tip: Coordinate office days with your team for better collaboration!'")
    
        # Validation 4: Benefits section should have bulleted lists (not numbered)
        if benefits_idx is None:
            errors.append("[X] heading_2 'Benefits' not found")
        else:
            checks_passed.append("[C] heading_2 'Benefits' found")
    
        # Find the end of Benefits section (either end of page or next heading_2)
        benefits_end_idx = len(page_blocks_sorted)
        for idx in range(benefits_idx + 1, len(page_blocks_sorted)):
            block = page_blocks_sorted[idx]
            if block.get("type") == "heading2":
                benefits_end_idx = idx
                break
    
        # Collect all list items in Benefits section
        benefits_list_items = []
        for idx in range(benefits_idx + 1, benefits_end_idx):
            block = page_blocks_sorted[idx]
            block_type = block.get("type", "")
        
            if block_type == "numberedList":
                errors.append(f"[X] Benefits section still contains numberedList: '{block.get('content')}'. All items should be bulletedList.")
            else:
                checks_passed.append(f"[C] Benefits section still contains numberedList: '{block.get('content')}'. All items should be bulletedList.")
        
            if block_type == "bulletedList":
                benefits_list_items.append(block)
    
        # Verify original benefits content is preserved
        original_benefits = [
            "comprehensive health insurance",
            "401(k) matching up to 4%",
            "annual learning stipend of $2,000",
            "home office setup allowance"
        ]
    
        benefits_content = [item.get("content", "").lower() for item in benefits_list_items]
    
        for benefit in original_benefits:
            found = False
            for content in benefits_content:
                if benefit in content:
                    found = True
                    break
            if not found:
                errors.append(f"[X] Original benefit '{benefit}' not found in Benefits section")
            else:
                checks_passed.append(f"[C] Original benefit '{benefit}' found in Benefits section")
    
        # Validation 5: New wellness benefit should be added
        wellness_benefit = "monthly wellness reimbursement of $150"
        wellness_found = False
        wellness_idx = None
    
        for idx, item in enumerate(benefits_list_items):
            content = item.get("content", "").lower()
            if "wellness" in content and "150" in content:
                wellness_found = True
                wellness_idx = idx
                break
    
        if not wellness_found:
            errors.append(f"[X] New benefit 'Monthly wellness reimbursement of $150' not found")
        else:
            checks_passed.append(f"[C] New benefit 'Monthly wellness reimbursement of $150' found")
    
        # Verify wellness benefit is the last item
        if wellness_idx != len(benefits_list_items) - 1:
            errors.append(f"[X] Wellness benefit should be the last bullet point in Benefits section (found at position {wellness_idx + 1} of {len(benefits_list_items)})")
        else:
            checks_passed.append(f"[C] Wellness benefit should be the last bullet point in Benefits section (found at position {wellness_idx + 1} of {len(benefits_list_items)})")
    
        # Verify Our Values section content is intact
        # Find the end of Our Values section
        our_values_end_idx = benefits_idx  # Our Values should end before Benefits
        for idx in range(our_values_idx + 1, len(page_blocks_sorted)):
            block = page_blocks_sorted[idx]
            if block.get("type") == "heading2":
                our_values_end_idx = idx
                break
    
        # Check that Our Values has its original bulleted list items
        our_values_items = []
        for idx in range(our_values_idx + 1, our_values_end_idx):
            block = page_blocks_sorted[idx]
            if block.get("type") == "bulletedList":
                our_values_items.append(block.get("content", "").lower())
    
        original_values = [
            "customer first",
            "excellence",
            "collaboration"
        ]
    
        for value in original_values:
            found = False
            for content in our_values_items:
                if value in content:
                    found = True
                    break
            if not found:
                errors.append(f"[X] Original value '{value}' not found in Our Values section - content may not be preserved")
            else:
                checks_passed.append(f"[C] Original value '{value}' found in Our Values section - content may be preserved")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

    # -----------------------------------------------------------------------------
    # Task: meeting-analysis-report
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_meeting_analysis_report(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate comprehensive meeting analysis report.
    
    Success criteria:
    1. 'Meeting Analysis Report' page exists as child of 'Meeting Notes'
    2. Page has heading_1 '📊 Meeting Analysis Report'
    3. Page has heading_2 '📅 Meeting Overview' with paragraph showing correct meeting count
    4. Page has heading_2 '🗂️ Meetings by Parent Page' with proper grouping
    5. Each parent group has heading_3 with parent title/icon and bulleted list of meeting titles
    6. Page has heading_2 '📈 Meeting Frequency Analysis' with yellow callout
    7. Callout contains numbered list of meeting count by month
    8. Page has heading_2 '⭐ Favorited Meetings' with only favorited meeting pages
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    
    # 1. Find 'Meeting Notes' page
    try:
        meeting_notes_page = _find_page_by_title(final_state_backend, "Meeting Notes")
        if not meeting_notes_page:
            errors.append("[X] Meeting Notes page not found")
        else:
            checks_passed.append("[C] Meeting Notes page found")
    
        # 2. Find 'Meeting Analysis Report' page as child of Meeting Notes
        analysis_report = _find_page_by_title(final_state_backend, "Meeting Analysis Report")
        if not analysis_report:
            errors.append("[X] Meeting Analysis Report page not found")
        else:
            checks_passed.append("[C] Meeting Analysis Report page found")

        if not _check_page_is_child_of(meeting_notes_page, analysis_report):
            errors.append("[X] Meeting Analysis Report is not a child of Meeting Notes")
        else:
            checks_passed.append("[C] Meeting Analysis Report is a child of Meeting Notes")

        # 3. Get all pages with 'Meeting' in title for validation
        meeting_pages_result = final_state_backend.query({
            "collection": "pages",
            "filter": {"title": {"$regex": "meeting", "$options": "i"}}
        })
        meeting_pages = meeting_pages_result if isinstance(meeting_pages_result, list) else []
        total_meeting_count = len(meeting_pages)

        if total_meeting_count == 0:
            errors.append("[X] No pages with 'Meeting' in title found in workspace")
        else:
            checks_passed.append("[C] pages with 'Meeting' in title found in workspace")

        # 4. Group meetings by parent page
        meetings_by_parent: Dict[str, List[Dict[str, Any]]] = {}
        parent_page_info: Dict[str, Dict[str, Any]] = {}

        for meeting_page in meeting_pages:
            parent_id = meeting_page.get("parentId")
            if parent_id:
                if parent_id not in meetings_by_parent:
                    meetings_by_parent[parent_id] = []
                    # Find parent page info by ID
                    parent_result = final_state_backend.query({
                        "collection": "pages",
                        "filter": {"_id": parent_id}
                    })
                    parent_page = parent_result[0] if isinstance(parent_result, list) and parent_result else None
                    if parent_page:
                        parent_page_info[parent_id] = parent_page
                meetings_by_parent[parent_id].append(meeting_page)
    
        # 5. Calculate meeting frequency by month
        meetings_by_month: Dict[str, int] = {}
        for meeting_page in meeting_pages:
            created_at = meeting_page.get("createdAt", "")
            if created_at:
                # Extract year-month from createdAt (format: "2026-01-06T13:18:16.588Z")
                try:
                    if isinstance(created_at, str) and len(created_at) >= 7:
                        year_month = created_at[:7]  # "2026-01"
                        if year_month not in meetings_by_month:
                            meetings_by_month[year_month] = 0
                        meetings_by_month[year_month] += 1
                except Exception:
                    pass
    
        # 6. Get favorited meetings
        favorited_meetings = [p for p in meeting_pages if p.get("isFavorite", False)]
    
        # 7. Get blocks from Meeting Analysis Report page
        report_id = analysis_report.get("_id")
        page_blocks = _get_blocks_for_page(final_state_backend, report_id)
    
        if not page_blocks:
            errors.append("[X] No blocks found on Meeting Analysis Report page")
        else:
            checks_passed.append("[C] blocks found on Meeting Analysis Report page")
    
        # Sort blocks by order
        page_blocks_sorted = sorted(page_blocks, key=lambda b: b.get("order", 0))
    
        # 8. Validate heading_1 '📊 Meeting Analysis Report'
        heading1_found = False
        for block in page_blocks_sorted:
            if block.get("type") == "heading1":
                content = block.get("content", "")
                if "meeting analysis report" in content.lower():
                    heading1_found = True
                    break
    
        if not heading1_found:
            errors.append("[X] heading_1 '📊 Meeting Analysis Report' not found")
        else:
            checks_passed.append("[C] heading_1 '📊 Meeting Analysis Report' found")
    
        # 9. Validate heading_2 '📅 Meeting Overview' and count paragraph
        overview_heading_idx = None
        for idx, block in enumerate(page_blocks_sorted):
            if block.get("type") == "heading2":
                content = block.get("content", "")
                if "meeting overview" in content.lower():
                    overview_heading_idx = idx
                    break
    
        if overview_heading_idx is None:
            errors.append("[X] heading_2 '📅 Meeting Overview' not found")
        else:
            checks_passed.append("[C] heading_2 '📅 Meeting Overview' found")
    
        # Check for count paragraph
        count_paragraph_found = False
        for idx in range(overview_heading_idx + 1, min(overview_heading_idx + 5, len(page_blocks_sorted))):
            block = page_blocks_sorted[idx]
            if block.get("type") == "paragraph":
                content = block.get("content", "").lower()
                if "total meetings found" in content:
                    # Verify the count is present
                    if str(total_meeting_count) in block.get("content", ""):
                        count_paragraph_found = True
                    else:
                        errors.append(f"[X] Meeting count in paragraph ({block.get('content')}) doesn't match actual count ({total_meeting_count})")
                    break
            elif block.get("type") == "heading2":
                break
    
        if not count_paragraph_found:
            errors.append(f"[X] Paragraph with 'Total meetings found: {total_meeting_count}' not found")
        else:
            checks_passed.append(f"[C] Paragraph with 'Total meetings found: {total_meeting_count}' found")
    
        # 10. Validate heading_2 '🗂️ Meetings by Parent Page' and grouping
        parent_heading_idx = None
        for idx, block in enumerate(page_blocks_sorted):
            if block.get("type") == "heading2":
                content = block.get("content", "")
                if "meetings by parent" in content.lower():
                    parent_heading_idx = idx
                    break
    
        if parent_heading_idx is None:
            errors.append("[X] heading_2 '🗂️ Meetings by Parent Page' not found")
        else:
            checks_passed.append("[C] heading_2 '🗂️ Meetings by Parent Page' found")
    
        # Find the next major heading_2 to determine section boundaries
        next_heading2_idx = len(page_blocks_sorted)
        for idx in range(parent_heading_idx + 1, len(page_blocks_sorted)):
            block = page_blocks_sorted[idx]
            if block.get("type") == "heading2":
                content = block.get("content", "").lower()
                if "meeting frequency" in content or "favorited" in content:
                    next_heading2_idx = idx
                    break
    
        # Validate parent groupings within the section
        parent_groups_found = 0
        for idx in range(parent_heading_idx + 1, next_heading2_idx):
            block = page_blocks_sorted[idx]
            if block.get("type") == "heading3":
                parent_groups_found += 1
    
        expected_parent_groups = len([pid for pid, meetings in meetings_by_parent.items() if len(meetings) > 0])
    
        if parent_groups_found < expected_parent_groups:
            errors.append(f"[X] Expected at least {expected_parent_groups} parent page groups (heading_3), found {parent_groups_found}")
        else:
            checks_passed.append(f"[C] Expected at least {expected_parent_groups} parent page groups (heading_3), found {parent_groups_found}")
    
        # Check for bulleted lists under each heading_3
        bulleted_lists_in_section = 0
        for idx in range(parent_heading_idx + 1, next_heading2_idx):
            block = page_blocks_sorted[idx]
            if block.get("type") == "bulletedList":
                bulleted_lists_in_section += 1
    
        if bulleted_lists_in_section < len(meeting_pages):
            errors.append(f"[X] Expected at least {len(meeting_pages)} bulleted list items for meeting titles, found {bulleted_lists_in_section}")
        else:
            checks_passed.append(f"[C] Expected at least {len(meeting_pages)} bulleted list items for meeting titles, found {bulleted_lists_in_section}")
    
        # 11. Validate heading_2 '📈 Meeting Frequency Analysis' and yellow callout
        frequency_heading_idx = None
        for idx, block in enumerate(page_blocks_sorted):
            if block.get("type") == "heading2":
                content = block.get("content", "")
                if "meeting frequency" in content.lower():
                    frequency_heading_idx = idx
                    break
    
        if frequency_heading_idx is None:
            errors.append("[X] heading_2 '📈 Meeting Frequency Analysis' not found")
        else:
            checks_passed.append("[C] heading_2 '📈 Meeting Frequency Analysis' found")
    
        # Find yellow callout with 📊 icon
        callout_found = False
        callout_idx = None
        for idx in range(frequency_heading_idx + 1, len(page_blocks_sorted)):
            block = page_blocks_sorted[idx]
            if block.get("type") == "callout":
                props = block.get("properties", {})
                bg_color = props.get("backgroundColor", "").lower()
                icon = props.get("icon", "")
                content = block.get("content", "").lower()
            
                if "yellow" in bg_color and icon == "📊":
                    callout_found = True
                    callout_idx = idx
                    if "based on creation dates" not in content:
                        errors.append("[X] Callout should contain 'Based on creation dates:'")
                    else:
                        checks_passed.append("[C] Callout should contain 'Based on creation dates:'")
                    break
            elif block.get("type") == "heading2":
                break
    
        if not callout_found:
            errors.append("[X] Yellow callout with 📊 icon not found under Meeting Frequency Analysis")
        else:
            checks_passed.append("[C] Yellow callout with 📊 icon found under Meeting Frequency Analysis")
    
        # Check for numbered list showing meeting count by month
        numbered_list_items = []
        for idx in range(callout_idx + 1 if callout_idx else frequency_heading_idx + 1, len(page_blocks_sorted)):
            block = page_blocks_sorted[idx]
            if block.get("type") == "numberedList":
                numbered_list_items.append(block)
            elif block.get("type") in ["heading2", "divider"]:
                break
    
        if len(numbered_list_items) == 0:
            errors.append("[X] No numbered list items found for meeting frequency by month")
        else:
            checks_passed.append("[C] numbered list items found for meeting frequency by month")
    
        # Verify month entries are present
        if len(meetings_by_month) > 0 and len(numbered_list_items) < len(meetings_by_month):
            errors.append(f"[X] Expected {len(meetings_by_month)} month entries in numbered list, found {len(numbered_list_items)}")
        else:
            checks_passed.append(f"[C] Expected {len(meetings_by_month)} month entries in numbered list, found {len(numbered_list_items)}")
    
        # 12. Validate heading_2 '⭐ Favorited Meetings'
        favorites_heading_idx = None
        for idx, block in enumerate(page_blocks_sorted):
            if block.get("type") == "heading2":
                content = block.get("content", "")
                if "favorited meetings" in content.lower():
                    favorites_heading_idx = idx
                    break
    
        if favorites_heading_idx is None:
            errors.append("[X] heading_2 '⭐ Favorited Meetings' not found")
        else:
            checks_passed.append("[C] heading_2 '⭐ Favorited Meetings' found")
    
        # Check favorited meetings are listed correctly
        favorited_list_items = []
        for idx in range(favorites_heading_idx + 1, len(page_blocks_sorted)):
            block = page_blocks_sorted[idx]
            if block.get("type") in ["bulletedList", "numberedList", "paragraph"]:
                content = block.get("content", "")
                if content:  # Non-empty content
                    favorited_list_items.append(content)
            elif block.get("type") in ["heading2", "divider"]:
                break
    
        # Verify favorited meetings count matches
        expected_favorited_count = len(favorited_meetings)
    
        if expected_favorited_count == 0:
            # If no favorites, there should be a message saying "No favorited meetings" or similar
            # Or the section could be empty
            pass  # Allow empty favorites section
        else:
            # Check that we have entries for favorited meetings
            if len(favorited_list_items) < expected_favorited_count:
                errors.append(f"[X] Expected {expected_favorited_count} favorited meetings listed, found {len(favorited_list_items)}")
            else:
                checks_passed.append(f"[C] Expected {expected_favorited_count} favorited meetings listed, found {len(favorited_list_items)}")
        
            # Verify favorited meeting titles appear in the list
            favorited_titles = [p.get("title", "").lower() for p in favorited_meetings]
            for fav_title in favorited_titles:
                found = False
                for item_content in favorited_list_items:
                    if fav_title in item_content.lower() or item_content.lower() in fav_title:
                        found = True
                        break
                if not found:
                    errors.append(f"[X] Favorited meeting '{fav_title}' not found in Favorited Meetings section")
                else:
                    checks_passed.append(f"[C] Favorited meeting '{fav_title}' found in Favorited Meetings section")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

    # -----------------------------------------------------------------------------
    # Task: documentation-index-2
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_documentation_index_2(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate documentation index page creation.
    
    Success criteria:
    1. '🗂️ Documentation Index' page exists as child of 'Project Documentation'
    2. Page has heading_1 '🗂️ Complete Documentation Index'
    3. Page has heading_2 '📊 Documentation Overview' followed by overview paragraph
    4. Page has heading_2 '🏗️ Architecture Documentation' with blue callout (📐 icon)
    5. Callout contains correct architecture page count
    6. Bulleted list shows correct hierarchy with proper indentation
    7. Page has heading_2 '⚡ Quick Links' with numbered list of links
    8. Page ends with divider and bold timestamp paragraph
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    
    # 1. Verify 'Project Documentation' page exists
    try:
        project_doc = _find_page_by_title(final_state_backend, "Project Documentation")
        if not project_doc:
            errors.append("[X] Project Documentation page not found")
        else:
            checks_passed.append("[C] Project Documentation page found")
    
        # 2. Verify '🗂️ Documentation Index' page exists as child of Project Documentation
        doc_index = _find_page_by_title(final_state_backend, "🗂️ Documentation Index")
        if not doc_index:
            # Try without emoji
            doc_index = _find_page_by_title(final_state_backend, "Documentation Index")
            if not doc_index:
                errors.append("[X] Documentation Index page not found")
            else:
                checks_passed.append("[C] Documentation Index page found")
    
        if not _check_page_is_child_of(project_doc, doc_index):
            errors.append("[X] Documentation Index is not a child of Project Documentation")
        else:
            checks_passed.append("[C] Documentation Index is a child of Project Documentation")
    
        # 3. Get blocks from Documentation Index page
        doc_index_id = doc_index.get("_id")
        page_blocks = _get_blocks_for_page(final_state_backend, doc_index_id)
    
        if not page_blocks:
            errors.append("[X] No blocks found on Documentation Index page")
        else:
            checks_passed.append("[C] blocks found on Documentation Index page")
    
        # Sort blocks by order
        page_blocks_sorted = sorted(page_blocks, key=lambda b: b.get("order", 0))
    
        # 4. Validate heading_1 '🗂️ Complete Documentation Index'
        heading1_found = False
        heading1_idx = None
        for idx, block in enumerate(page_blocks_sorted):
            if block.get("type") == "heading1":
                content = block.get("content", "")
                if "complete documentation index" in content.lower():
                    heading1_found = True
                    heading1_idx = idx
                    break
    
        if not heading1_found:
            errors.append("[X] heading_1 '🗂️ Complete Documentation Index' not found")
        else:
            checks_passed.append("[C] heading_1 '🗂️ Complete Documentation Index' found")
    
        # 5. Validate heading_2 '📊 Documentation Overview' and overview paragraph
        overview_heading_found = False
        overview_heading_idx = None
        for idx, block in enumerate(page_blocks_sorted):
            if block.get("type") == "heading2":
                content = block.get("content", "")
                if "documentation overview" in content.lower():
                    overview_heading_found = True
                    overview_heading_idx = idx
                    break
    
        if not overview_heading_found:
            errors.append("[X] heading_2 '📊 Documentation Overview' not found")
        else:
            checks_passed.append("[C] heading_2 '📊 Documentation Overview' found")
    
        # Check for overview paragraph after the heading
        overview_paragraph_found = False
        for idx in range(overview_heading_idx + 1, min(overview_heading_idx + 3, len(page_blocks_sorted))):
            block = page_blocks_sorted[idx]
            if block.get("type") == "paragraph":
                content = block.get("content", "").lower()
                if "hierarchical view" in content or "project documentation" in content:
                    overview_paragraph_found = True
                    break
            elif block.get("type") == "heading2":
                break
    
        if not overview_paragraph_found:
            errors.append("[X] Overview paragraph about hierarchical view not found")
        else:
            checks_passed.append("[C] Overview paragraph about hierarchical view found")
    
        # 6. Validate heading_2 '🏗️ Architecture Documentation' and blue callout
        arch_heading_found = False
        arch_heading_idx = None
        for idx, block in enumerate(page_blocks_sorted):
            if block.get("type") == "heading2":
                content = block.get("content", "")
                if "architecture documentation" in content.lower():
                    arch_heading_found = True
                    arch_heading_idx = idx
                    break
    
        if not arch_heading_found:
            errors.append("[X] heading_2 '🏗️ Architecture Documentation' not found")
        else:
            checks_passed.append("[C] heading_2 '🏗️ Architecture Documentation' found")
    
        # 7. Find and validate the blue callout with 📐 icon
        callout_found = False
        callout_idx = None
        architecture_page_count = None
    
        for idx in range(arch_heading_idx + 1, len(page_blocks_sorted)):
            block = page_blocks_sorted[idx]
            if block.get("type") == "callout":
                props = block.get("properties", {})
                bg_color = props.get("backgroundColor", "")
                icon = props.get("icon", "")
            
                if "blue" in bg_color.lower() and icon == "📐":
                    callout_found = True
                    callout_idx = idx
                    content = block.get("content", "")
                
                    # Extract the architecture page count
                    if "total architecture pages" in content.lower():
                        # Try to extract the number
                        import re
                        match = re.search(r'total architecture pages[:\s]*(\d+)', content.lower())
                        if match:
                            architecture_page_count = int(match.group(1))
                    break
            elif block.get("type") == "heading2":
                # Stop if we hit another heading_2
                break
    
        if not callout_found:
            errors.append("[X] Blue callout with 📐 icon not found under Architecture Documentation")
        else:
            checks_passed.append("[C] Blue callout with 📐 icon found under Architecture Documentation")
    
        # 8. Count actual architecture pages for verification
        # Find Architecture page
        arch_page = _find_page_by_title(final_state_backend, "Architecture")
        if not arch_page:
            errors.append("[X] Architecture page not found for count verification")
        else:
            checks_passed.append("[C] Architecture page found for count verification")
    
        # Count Architecture and all its descendants
        def count_descendants(page_id: str, depth: int = 0) -> int:
            count = 1  # Count this page
            children = _get_child_pages(final_state_backend, page_id)
            for child in children:
                count += count_descendants(child.get("_id"), depth + 1)
            return count
    
        expected_arch_count = count_descendants(arch_page.get("_id"))
    
        if architecture_page_count is not None and architecture_page_count != expected_arch_count:
            errors.append(f"[X] Architecture page count mismatch: found {architecture_page_count}, expected {expected_arch_count}")
        else:
            checks_passed.append(f"[C] Architecture page count mismatch: found {architecture_page_count}, expected {expected_arch_count}")
    
        # 9. Validate bulleted list showing hierarchy
        expected_hierarchy = [
            ("architecture", 0),
            ("frontend architecture", 1),
            ("component library", 2),
            ("state management", 2),
            ("backend architecture", 1),
            ("api design patterns", 2),
        ]
    
        bulleted_list_items = []
        for idx in range(callout_idx + 1 if callout_idx else arch_heading_idx + 1, len(page_blocks_sorted)):
            block = page_blocks_sorted[idx]
            if block.get("type") == "bulletedList":
                bulleted_list_items.append(block)
            elif block.get("type") == "heading2":
                # Stop at next heading_2
                break
    
        if len(bulleted_list_items) < len(expected_hierarchy):
            errors.append(f"[X] Expected at least {len(expected_hierarchy)} bulleted list items for hierarchy, found {len(bulleted_list_items)}")
        else:
            checks_passed.append(f"[C] Expected at least {len(expected_hierarchy)} bulleted list items for hierarchy, found {len(bulleted_list_items)}")
    
        # Verify hierarchy items exist (case-insensitive)
        found_hierarchy_items = []
        for item in bulleted_list_items:
            content = item.get("content", "").lower().strip()
            # Remove bullet character and leading/trailing whitespace
            content = content.lstrip("•").strip()
            found_hierarchy_items.append(content)
    
        for expected_item, depth in expected_hierarchy:
            found = False
            for found_item in found_hierarchy_items:
                if expected_item in found_item or found_item in expected_item:
                    found = True
                    break
            if not found:
                errors.append(f"[X] Hierarchy item '{expected_item}' not found in bulleted list")
            else:
                checks_passed.append(f"[C] Hierarchy item '{expected_item}' found in bulleted list")
    
        # 10. Validate heading_2 '⚡ Quick Links' and numbered list
        quick_links_heading_found = False
        quick_links_idx = None
        for idx, block in enumerate(page_blocks_sorted):
            if block.get("type") == "heading2":
                content = block.get("content", "")
                if "quick links" in content.lower():
                    quick_links_heading_found = True
                    quick_links_idx = idx
                    break
    
        if not quick_links_heading_found:
            errors.append("[X] heading_2 '⚡ Quick Links' not found")
        else:
            checks_passed.append("[C] heading_2 '⚡ Quick Links' found")
    
        # Check for numbered list with Deployment Guide and CI/CD Pipeline
        numbered_list_items = []
        for idx in range(quick_links_idx + 1, len(page_blocks_sorted)):
            block = page_blocks_sorted[idx]
            if block.get("type") == "numberedList":
                numbered_list_items.append(block.get("content", ""))
            elif block.get("type") in ["heading2", "divider"]:
                break
    
        required_links = ["deployment guide", "ci/cd pipeline"]
        for required_link in required_links:
            found = False
            for item in numbered_list_items:
                if required_link in item.lower():
                    found = True
                    break
            if not found:
                errors.append(f"[X] Quick Links numbered list missing '{required_link}'")
            else:
                checks_passed.append(f"[C] Quick Links numbered list has '{required_link}'")
    
        # 11. Validate divider exists near the end
        divider_found = False
        divider_idx = None
        for idx in range(len(page_blocks_sorted) - 1, max(0, len(page_blocks_sorted) - 5), -1):
            block = page_blocks_sorted[idx]
            if block.get("type") == "divider":
                divider_found = True
                divider_idx = idx
                break
    
        if not divider_found:
            errors.append("[X] Divider not found near the end of the page")
        else:
            checks_passed.append("[C] Divider found near the end of the page")
    
        # 12. Validate bold timestamp paragraph at the end
        timestamp_paragraph_found = False
        for idx in range(divider_idx + 1 if divider_idx else len(page_blocks_sorted) - 3, len(page_blocks_sorted)):
            block = page_blocks_sorted[idx]
            if block.get("type") == "paragraph":
                content = block.get("content", "")
                content_lower = content.lower()
            
                # Check for timestamp pattern
                if "index generated" in content_lower or "generated" in content_lower:
                    timestamp_paragraph_found = True
                
                    # Check for bold formatting (content should contain bold markers or properties should indicate bold)
                    props = block.get("properties", {})
                    is_bold = props.get("bold", False)
                
                    # Also check if content has bold markdown syntax <b> or **
                    has_bold_markers = "<b>" in content or "**" in content or "<strong>" in content
                
                    if not is_bold and not has_bold_markers:
                        # Be lenient - just check if the paragraph exists with timestamp
                        pass  # Allow without explicit bold check for now
                    break
    
        if not timestamp_paragraph_found:
            errors.append("[X] Bold timestamp paragraph 'Index generated: [date/time]' not found at the end")
        else:
            checks_passed.append("[C] Bold timestamp paragraph 'Index generated: [date/time]' found at the end")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

    # -----------------------------------------------------------------------------
    # Task: engineering-team-dashboard
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_engineering_team_dashboard(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate engineering team dashboard creation.
    
    Success criteria:
    1. 'Engineering Team Dashboard' page exists as child of 'Engineering Wiki'
    2. Page starts with heading_1 '🚀 Engineering Team Dashboard'
    3. heading_2 '📋 Active Projects' followed by intro paragraph
    4. For each sub-page of 'Project Documentation' with >= 5 blocks:
       - heading_3 with page icon and title
       - callout with Gray background containing:
         - bold paragraph 'Quick Stats:'
         - bulletedList items with block count, child count, last updated
    5. Divider after all project sections
    6. heading_2 '🔗 Quick Links' with bookmark blocks to 'API Documentation' and 'Design System'
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    
    # 1. Verify 'Engineering Wiki' exists
    try:
        engineering_wiki = _find_page_by_title(final_state_backend, "Engineering Wiki")
        if not engineering_wiki:
            errors.append("[X] Engineering Wiki page not found")
        else:
            checks_passed.append("[C] Engineering Wiki page found")
    
        # 2. Verify 'Engineering Team Dashboard' exists as child of Engineering Wiki
        dashboard = _find_page_by_title(final_state_backend, "Engineering Team Dashboard")
        if not dashboard:
            errors.append("[X] Engineering Team Dashboard page not found")
        else:
            checks_passed.append("[C] Engineering Team Dashboard page found")
    
        if not _check_page_is_child_of(engineering_wiki, dashboard):
            errors.append("[X] Engineering Team Dashboard is not a child of Engineering Wiki")
        else:
            checks_passed.append("[C] Engineering Team Dashboard is a child of Engineering Wiki")
    
        # 3. Get blocks from the dashboard page
        dashboard_blocks = _get_blocks_for_page(final_state_backend, dashboard.get("_id"))
    
        if len(dashboard_blocks) < 5:  # Minimum expected blocks
            errors.append(f"[X] Engineering Team Dashboard has too few blocks ({len(dashboard_blocks)})")
        else:
            checks_passed.append(f"[C] Engineering Team Dashboard has too few blocks ({len(dashboard_blocks)})")
    
        block_idx = 0
    
        # 4. Validate heading_1 '🚀 Engineering Team Dashboard'
        if block_idx >= len(dashboard_blocks):
            errors.append("[X] Missing heading1 block")
        else:
            checks_passed.append("[C] has heading1 block")
        if dashboard_blocks[block_idx].get("type") != "heading1":
            errors.append(f"[X] Block {block_idx} should be heading1, got {dashboard_blocks[block_idx].get('type')}")
        else:
            checks_passed.append(f"[C] Block {block_idx} should be heading1, got {dashboard_blocks[block_idx].get('type')}")
        heading1_content = dashboard_blocks[block_idx].get("content", "").lower()
        if "engineering team dashboard" not in heading1_content:
            errors.append("[X] heading1 should contain 'Engineering Team Dashboard'")
        else:
            checks_passed.append("[C] heading1 should contain 'Engineering Team Dashboard'")
        block_idx += 1
    
        # 5. Validate heading_2 '📋 Active Projects'
        if block_idx >= len(dashboard_blocks):
            errors.append("[X] Missing heading2 block for Active Projects")
        else:
            checks_passed.append("[C] has heading2 block for Active Projects")
        if dashboard_blocks[block_idx].get("type") != "heading2":
            errors.append(f"[X] Block {block_idx} should be heading2, got {dashboard_blocks[block_idx].get('type')}")
        else:
            checks_passed.append(f"[C] Block {block_idx} should be heading2, got {dashboard_blocks[block_idx].get('type')}")
        if "active projects" not in dashboard_blocks[block_idx].get("content", "").lower():
            errors.append("[X] heading2 should contain 'Active Projects'")
        else:
            checks_passed.append("[C] heading2 should contain 'Active Projects'")
        block_idx += 1
    
        # 6. Validate intro paragraph
        if block_idx >= len(dashboard_blocks):
            errors.append("[X] Missing intro paragraph after Active Projects heading")
        else:
            checks_passed.append("[C] has intro paragraph after Active Projects heading")
        if dashboard_blocks[block_idx].get("type") != "paragraph":
            errors.append(f"[X] Block {block_idx} should be paragraph, got {dashboard_blocks[block_idx].get('type')}")
        else:
            checks_passed.append(f"[C] Block {block_idx} should be paragraph, got {dashboard_blocks[block_idx].get('type')}")
        intro_content = dashboard_blocks[block_idx].get("content", "").lower()
        if "real-time overview" not in intro_content and "overview" not in intro_content:
            errors.append("[X] Intro paragraph should mention 'Real-time overview' or 'overview'")
        else:
            checks_passed.append("[C] Intro paragraph should mention 'Real-time overview' or 'overview'")
        block_idx += 1
    
        # 7. Find 'Project Documentation' and its sub-pages with >= 5 blocks
        project_doc = _find_page_by_title(final_state_backend, "Project Documentation")
        if not project_doc:
            errors.append("[X] Project Documentation page not found")
        else:
            checks_passed.append("[C] Project Documentation page found")
    
        project_doc_children = _get_child_pages(final_state_backend, project_doc.get("_id"))
    
        # Filter sub-pages with at least 5 blocks
        qualifying_subpages = []
        for child in project_doc_children:
            child_blocks = _get_blocks_for_page(final_state_backend, child.get("_id"))
            if len(child_blocks) >= 5:
                child_children = _get_child_pages(final_state_backend, child.get("_id"))
                qualifying_subpages.append({
                    "page": child,
                    "block_count": len(child_blocks),
                    "child_count": len(child_children),
                    "updated_at": child.get("updatedAt", "")
                })
    
        # 8. Validate project sections
        project_sections_validated = 0
    
        for subpage_info in qualifying_subpages:
            subpage = subpage_info["page"]
            expected_block_count = subpage_info["block_count"]
            expected_child_count = subpage_info["child_count"]
            subpage_title = subpage.get("title", "")
            subpage_icon = subpage.get("icon", "📄")
        
            # Look for heading_3 with page title
            found_section = False
            section_start_idx = None
        
            for i in range(block_idx, len(dashboard_blocks)):
                block = dashboard_blocks[i]
                if block.get("type") == "heading3":
                    block_content = block.get("content", "")
                    # Check if title is in the heading (icon may or may not be present)
                    if subpage_title.lower() in block_content.lower():
                        found_section = True
                        section_start_idx = i
                        break
        
            if not found_section:
                continue  # Skip if section not found for this subpage
        
            # Validate callout after heading_3
            callout_idx = section_start_idx + 1
            if callout_idx >= len(dashboard_blocks):
                errors.append(f"[X] Missing callout block after heading for '{subpage_title}'")
            else:
                checks_passed.append(f"[C] has callout block after heading for '{subpage_title}'")
        
            callout_block = dashboard_blocks[callout_idx]
            if callout_block.get("type") != "callout":
                errors.append(f"[X] Expected callout after heading for '{subpage_title}', got {callout_block.get('type')}")
            else:
                checks_passed.append(f"[C] Expected callout after heading for '{subpage_title}', got {callout_block.get('type')}")
        
            # Validate Gray background
            callout_props = callout_block.get("properties", {})
            bg_color = callout_props.get("backgroundColor", "").lower()
            if bg_color != "gray":
                errors.append(f"[X] Callout for '{subpage_title}' should have Gray background, got '{bg_color}'")
            else:
                checks_passed.append(f"[C] Callout for '{subpage_title}' should have Gray background, got '{bg_color}'")
        
            # Validate callout content contains Quick Stats
            callout_content = callout_block.get("content", "").lower()
            if "quick stats" not in callout_content:
                errors.append(f"[X] Callout for '{subpage_title}' should contain 'Quick Stats:'")
            else:
                checks_passed.append(f"[C] Callout for '{subpage_title}' should contain 'Quick Stats:'")
        
            # Validate block count in content
            if f"total blocks: {expected_block_count}" not in callout_content and f"blocks: {expected_block_count}" not in callout_content:
                # Be more lenient - just check the number appears
                if str(expected_block_count) not in callout_content:
                    errors.append(f"[X] Callout for '{subpage_title}' should show block count {expected_block_count}")
                else:
                    checks_passed.append(f"[C] Callout for '{subpage_title}' should show block count {expected_block_count}")
        
            # Validate child count (sub-pages count)
            if str(expected_child_count) not in callout_content:
                errors.append(f"[X] Callout for '{subpage_title}' should show sub-pages count {expected_child_count}")
            else:
                checks_passed.append(f"[C] Callout for '{subpage_title}' should show sub-pages count {expected_child_count}")
        
            project_sections_validated += 1
    
        if project_sections_validated == 0 and len(qualifying_subpages) > 0:
            errors.append("[X] No project sections with proper structure found")
        else:
            checks_passed.append("[C] project sections with proper structure found")
    
        # 9. Find divider
        divider_found = False
        divider_idx = None
        for i in range(len(dashboard_blocks)):
            if dashboard_blocks[i].get("type") == "divider":
                divider_found = True
                divider_idx = i
                break
    
        if not divider_found:
            errors.append("[X] Divider not found after project sections")
        else:
            checks_passed.append("[C] Divider found after project sections")
    
        # 10. Validate Quick Links section
        quick_links_heading_found = False
        quick_links_idx = None
    
        for i in range(divider_idx + 1 if divider_idx else 0, len(dashboard_blocks)):
            block = dashboard_blocks[i]
            if block.get("type") == "heading2":
                if "quick links" in block.get("content", "").lower():
                    quick_links_heading_found = True
                    quick_links_idx = i
                    break
    
        if not quick_links_heading_found:
            errors.append("[X] heading2 '🔗 Quick Links' not found after divider")
        else:
            checks_passed.append("[C] heading2 '🔗 Quick Links' found after divider")
    
        # 11. Validate bookmark blocks for API Documentation and Design System
        api_doc_page = _find_page_by_title(final_state_backend, "API Documentation")
        design_system_page = _find_page_by_title(final_state_backend, "Design System")
    
        api_bookmark_found = False
        design_system_bookmark_found = False
    
        for i in range(quick_links_idx + 1 if quick_links_idx else 0, len(dashboard_blocks)):
            block = dashboard_blocks[i]
            if block.get("type") == "bookmark":
                props = block.get("properties", {})
                url = props.get("url", "")
                content = block.get("content", "").lower()
            
                # Check for API Documentation bookmark
                if api_doc_page:
                    api_title = api_doc_page.get("title", "").lower()
                    if api_title in content or "api documentation" in content or "api" in content.lower():
                        api_bookmark_found = True
            
                # Check for Design System bookmark
                if design_system_page:
                    design_title = design_system_page.get("title", "").lower()
                    if design_title in content or "design system" in content:
                        design_system_bookmark_found = True
    
        if not api_bookmark_found:
            errors.append("[X] Bookmark for 'API Documentation' not found in Quick Links")
        else:
            checks_passed.append("[C] Bookmark for 'API Documentation' found in Quick Links")
    
        if not design_system_bookmark_found:
            errors.append("[X] Bookmark for 'Design System' not found in Quick Links")
        else:
            checks_passed.append("[C] Bookmark for 'Design System' found in Quick Links")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

    # -----------------------------------------------------------------------------
    # Task: prd-user-stories-priority-matrix
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_prd_user_stories_priority_matrix(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate PRD User Stories Priority Matrix task.
    
    Success criteria:
    1. '📋 User Stories - Priority Matrix' heading_3 is positioned between 
       'User Stories - Part 2' heading and its description paragraph
    2. Purple callout with 🎯 icon contains exact text 
       'High-priority user stories require immediate attention'
    3. Four numbered list items appear in specified order:
       - '1. Critical: Payment processing flow optimization'
       - '2. High: Mobile responsive design implementation'
       - '3. Medium: Advanced search filters'
       - '4. Low: Theme customization options'
    4. Divider appears after last bullet of Overview section, before User Stories heading
    5. Bold paragraph with document status shows today's date
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    try:
        from datetime import datetime
    
    
    
        # 1. Find 'Comprehensive Product Requirements Document' page
        prd_page = _find_page_by_title(final_state_backend, "Comprehensive Product Requirements Document")
        if not prd_page:
            errors.append("[X] Comprehensive Product Requirements Document page not found")
        else:
            checks_passed.append("[C] Comprehensive Product Requirements Document page found")
    
        page_id = prd_page.get("_id")
        page_blocks = _get_blocks_for_page(final_state_backend, page_id)
    
        if not page_blocks:
            errors.append("[X] No blocks found on Comprehensive Product Requirements Document page")
        else:
            checks_passed.append("[C] blocks found on Comprehensive Product Requirements Document page")
    
        # Sort blocks by order to ensure correct sequence
        page_blocks_sorted = sorted(page_blocks, key=lambda b: b.get("order", 0))
    
        # 2. Find key positions in the document
        user_stories_part_2_idx = None
        user_stories_heading_idx = None
        overview_section_idx = None
        overview_last_bullet_idx = None
        priority_matrix_heading_idx = None
    
        # Track indices for validation
        for idx, block in enumerate(page_blocks_sorted):
            block_type = block.get("type", "")
            content = block.get("content", "")
            content_lower = content.lower()
        
            # Find 'User Stories - Part 2' heading_3
            if block_type == "heading3" and "user stories - part 2" in content_lower:
                user_stories_part_2_idx = idx
        
            # Find 'User Stories' heading_2 (the section header)
            if block_type == "heading2" and "user stories" in content_lower and "part" not in content_lower:
                user_stories_heading_idx = idx
        
            # Find 'Overview' heading_2
            if block_type == "heading2" and "overview" in content_lower:
                overview_section_idx = idx
        
            # Find the new priority matrix heading
            if block_type == "heading3" and "user stories - priority matrix" in content_lower:
                priority_matrix_heading_idx = idx
    
        # 3. Validate priority matrix heading exists and is positioned correctly
        if priority_matrix_heading_idx is None:
            errors.append("[X] Missing heading_3 '📋 User Stories - Priority Matrix'")
        else:
            checks_passed.append("[C] has heading_3 '📋 User Stories - Priority Matrix'")
    
        if user_stories_part_2_idx is None:
            errors.append("[X] 'User Stories - Part 2' heading not found")
        else:
            checks_passed.append("[C] 'User Stories - Part 2' heading found")
    
        # Verify position: priority matrix must come after 'User Stories - Part 2'
        if priority_matrix_heading_idx <= user_stories_part_2_idx:
            errors.append(f"[X] Priority Matrix heading (idx {priority_matrix_heading_idx}) must appear  after User Stories - Part 2 (idx {user_stories_part_2_idx})")
        else:
            checks_passed.append(f"[C] Priority Matrix heading (idx {priority_matrix_heading_idx}) must appear after User Stories - Part 2 (idx {user_stories_part_2_idx})")
    
        # Check that priority matrix heading is before the next major heading
        # and after Part 2 but before Part 2's description ends (i.e., closely after Part 2)
        # Allow up to 2 blocks between Part 2 and Priority Matrix (to account for description paragraph)
        if priority_matrix_heading_idx - user_stories_part_2_idx > 2:
            # Check if there's a paragraph immediately after Part 2 (description)
            # and Priority Matrix should be either right after Part 2 or after that paragraph
            desc_para_idx = user_stories_part_2_idx + 1
            if desc_para_idx < len(page_blocks_sorted):
                desc_block = page_blocks_sorted[desc_para_idx]
                if desc_block.get("type") == "paragraph":
                    # Priority Matrix should ideally be between Part 2 heading and description paragraph
                    # But if it's right after description, that's acceptable for now
                    if priority_matrix_heading_idx > desc_para_idx + 3:
                        errors.append(f"[X] Priority Matrix heading should be positioned immediately after  User Stories - Part 2 heading, not {priority_matrix_heading_idx - user_stories_part_2_idx} blocks later")
                    else:
                        checks_passed.append(f"[C] Priority Matrix heading should be positioned immediately after User Stories - Part 2 heading, {priority_matrix_heading_idx - user_stories_part_2_idx} blocks later")
    
        # 4. Find and validate the callout block with purple background and 🎯 icon
        callout_found = False
        callout_valid = False
        callout_idx = None
    
        # Look for callout after the priority matrix heading
        for idx in range(priority_matrix_heading_idx + 1, min(priority_matrix_heading_idx + 10, len(page_blocks_sorted))):
            block = page_blocks_sorted[idx]
            if block.get("type") == "callout":
                callout_found = True
                callout_idx = idx
                props = block.get("properties", {})
                content = block.get("content", "")
            
                bg_color = props.get("backgroundColor", "").lower()
                icon = props.get("icon", "")
            
                # Check for purple background
                if "purple" not in bg_color:
                    errors.append(f"[X] Callout should have Purple background, got '{props.get('backgroundColor')}'")
                else:
                    checks_passed.append(f"[C] Callout should have Purple background, got '{props.get('backgroundColor')}'")
            
                # Check for 🎯 icon
                if icon != "🎯":
                    errors.append(f"[X] Callout should have 🎯 icon, got '{icon}'")
                else:
                    checks_passed.append(f"[C] Callout should have 🎯 icon, got '{icon}'")
            
                # Check for exact text content
                if "high-priority user stories require immediate attention" not in content.lower():
                    errors.append(f"[X] Callout should contain High-priority user stories require immediate attention,  got {content}")
                else:
                    checks_passed.append(f"[C] Callout should contain High-priority user stories require immediate attention, got {content}")
            
                callout_valid = True
                break
    
        if not callout_found:
            errors.append("[X] Callout block with purple background and 🎯 icon not found after Priority Matrix heading")
        else:
            checks_passed.append("[C] Callout block with purple background and 🎯 icon found after Priority Matrix heading")
    
        if not callout_valid:
            errors.append("[X] Callout block validation failed")
        else:
            checks_passed.append("[C] Callout block validation succeeded")
    
        # 5. Validate the four numbered list items in order
        expected_items = [
            "critical: payment processing flow optimization",
            "high: mobile responsive design implementation",
            "medium: advanced search filters",
            "low: theme customization options"
        ]
    
        numbered_list_items = []
        search_start = callout_idx + 1 if callout_idx else priority_matrix_heading_idx + 1
    
        for idx in range(search_start, min(search_start + 10, len(page_blocks_sorted))):
            block = page_blocks_sorted[idx]
            if block.get("type") == "numberedList":
                numbered_list_items.append(block)
            elif block.get("type") in ["heading2", "heading3", "divider"] and len(numbered_list_items) > 0:
                # Stop at next structural element after finding some items
                break
    
        if len(numbered_list_items) != 4:
            errors.append(f"[X] Expected exactly 4 numbered list items, found {len(numbered_list_items)}")
        else:
            checks_passed.append(f"[C] Expected exactly 4 numbered list items, found {len(numbered_list_items)}")
    
        # Validate each item in order
        for i, (item, expected) in enumerate(zip(numbered_list_items, expected_items)):
            item_content = item.get("content", "").lower()
            # Remove the number prefix if present (e.g., "1. ", "2. ")
            item_content_cleaned = item_content.lstrip("0123456789. ").strip()
        
            if expected not in item_content and expected not in item_content_cleaned:
                errors.append(f"[X] Numbered list item {i + 1} should contain {expected},  got {item.get('content')}")
            else:
                checks_passed.append(f"[C] Numbered list item {i + 1} should contain {expected}, got {item.get('content')}")
    
        # 6. Validate divider and document status paragraph after Overview section
        if overview_section_idx is None:
            errors.append("[X] 'Overview' section heading not found")
        else:
            checks_passed.append("[C] 'Overview' section heading found")
    
        if user_stories_heading_idx is None:
            errors.append("[X] 'User Stories' section heading not found")
        else:
            checks_passed.append("[C] 'User Stories' section heading found")
    
        # Find the last bullet point in Overview section (between Overview heading and User Stories heading)
        for idx in range(user_stories_heading_idx - 1, overview_section_idx, -1):
            block = page_blocks_sorted[idx]
            if block.get("type") == "bulletedList":
                overview_last_bullet_idx = idx
                break
    
        if overview_last_bullet_idx is None:
            errors.append("[X] No bullet points found in Overview section")
        else:
            checks_passed.append("[C] bullet points found in Overview section")
    
        # Look for divider after the last bullet but before User Stories heading
        divider_found = False
        divider_idx = None
        status_paragraph_found = False
        status_paragraph_valid = False
    
        for idx in range(overview_last_bullet_idx + 1, user_stories_heading_idx):
            block = page_blocks_sorted[idx]
            block_type = block.get("type", "")
        
            if block_type == "divider":
                divider_found = True
                divider_idx = idx
        
            if block_type == "paragraph" and divider_found:
                content = block.get("content", "")
                content_lower = content.lower()
            
                # Check for document status text
                if "document status" in content_lower and "in review" in content_lower:
                    status_paragraph_found = True
                
                    # Check for bold formatting (marked with ** or contained in bold marker)
                    if "**" in content or "document status:" in content_lower:
                        # Check for date reference - accept any date format
                        # Today's date could be in various formats
                        today = datetime.now()
                        date_patterns = [
                            today.strftime("%Y-%m-%d"),  # 2026-01-07
                            today.strftime("%m/%d/%Y"),  # 01/07/2026
                            today.strftime("%d/%m/%Y"),  # 07/01/2026
                            today.strftime("%B %d, %Y"),  # January 07, 2026
                            today.strftime("%b %d, %Y"),  # Jan 07, 2026
                            today.strftime("%d %B %Y"),   # 07 January 2026
                            today.strftime("%d %b %Y"),   # 07 Jan 2026
                            "today",
                            str(today.year),  # At minimum, should have the year
                        ]
                    
                        date_found = False
                        for pattern in date_patterns:
                            if pattern.lower() in content_lower:
                                date_found = True
                                break
                    
                        if date_found or "last modified" in content_lower:
                            status_paragraph_valid = True
                        else:
                            errors.append(f"[X] Document status paragraph should include todays date,  got: {content}")
                    else:
                        errors.append(f"[X] Document status paragraph should have bold text formatting,  got: {content}")
    
        if not divider_found:
            errors.append("[X] Divider not found between Overview section's last bullet and User Stories heading")
        else:
            checks_passed.append("[C] Divider found between Overview section's last bullet and User Stories heading")
    
        if not status_paragraph_found:
            errors.append("[X] Document status paragraph not found after divider")
        else:
            checks_passed.append("[C] Document status paragraph found after divider")
    
        if not status_paragraph_valid:
            errors.append("[X] Document status paragraph validation failed")
        else:
            checks_passed.append("[C] Document status paragraph validation succeeded")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

    # -----------------------------------------------------------------------------
    # Task: sprint-meeting-analytics
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_sprint_meeting_analytics(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate sprint meeting analytics section.
    
    Success criteria:
    1. Navigate to 'Sprint Planning - Jan 15' page (child of 'Meeting Notes')
    2. Analytics section must appear AFTER 'Action Items' section
    3. Section starts with divider, then heading_2 '📊 Meeting Analytics'
    4. Blue callout with '📈' icon containing exact meeting stats:
       - 'Meeting Duration: 2 hours (9:00 AM - 11:00 AM)'
       - 'Total Participants: 3'
       - 'Action Items Completion: 100%'
    5. heading_3 '👥 Participant Contributions' with bulleted list:
       - 'Alice Chen (Product): Create wireframes for sharing modal'
       - 'Bob Martinez (Engineering): Set up drag-and-drop library'
       - 'Carol Williams (Design): [none assigned]'
    6. heading_3 '🎯 Sprint Goals Status' with numbered list:
       - '✅ Complete authentication flow redesign'
       - '✅ Implement block drag-and-drop'
       - '✅ Add page sharing permissions UI'
    7. Italic paragraph: 'Meeting productivity score: Excellent (all action items completed)'
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    
    # 1. Find 'Meeting Notes' page
    try:
        meeting_notes_page = _find_page_by_title(final_state_backend, "Meeting Notes")
        if not meeting_notes_page:
            errors.append("[X] Meeting Notes page not found")
        else:
            checks_passed.append("[C] Meeting Notes page found")
    
        # 2. Find 'Sprint Planning - Jan 15' page as child of Meeting Notes
        sprint_planning_page = _find_page_by_title(final_state_backend, "Sprint Planning - Jan 15")
        if not sprint_planning_page:
            errors.append("[X] Sprint Planning - Jan 15 page not found")
        else:
            checks_passed.append("[C] Sprint Planning - Jan 15 page found")
    
        if not _check_page_is_child_of(meeting_notes_page, sprint_planning_page):
            errors.append("[X] Sprint Planning - Jan 15 is not a child of Meeting Notes")
        else:
            checks_passed.append("[C] Sprint Planning - Jan 15 is a child of Meeting Notes")
    
        # 3. Get blocks from the Sprint Planning page
        page_id = sprint_planning_page.get("_id")
        page_blocks = _get_blocks_for_page(final_state_backend, page_id)
    
        if not page_blocks:
            errors.append("[X] No blocks found on Sprint Planning - Jan 15 page")
        else:
            checks_passed.append("[C] blocks found on Sprint Planning - Jan 15 page")
    
        # Sort blocks by order
        page_blocks_sorted = sorted(page_blocks, key=lambda b: b.get("order", 0))
    
        # 4. Find key positions in the document
        action_items_heading_idx = None
        meeting_analytics_heading_idx = None
        divider_before_analytics_idx = None
        participant_contributions_heading_idx = None
        sprint_goals_status_heading_idx = None
    
        for idx, block in enumerate(page_blocks_sorted):
            block_type = block.get("type", "")
            content = block.get("content", "")
            content_lower = content.lower() if content else ""
        
            # Find 'Action Items' heading_2
            if block_type == "heading2" and "action items" in content_lower:
                action_items_heading_idx = idx
        
            # Find divider
            if block_type == "divider" and action_items_heading_idx is not None:
                if divider_before_analytics_idx is None:
                    divider_before_analytics_idx = idx
        
            # Find '📊 Meeting Analytics' heading_2
            if block_type == "heading2" and "meeting analytics" in content_lower:
                meeting_analytics_heading_idx = idx
        
            # Find '👥 Participant Contributions' heading_3
            if block_type == "heading3" and "participant contributions" in content_lower:
                participant_contributions_heading_idx = idx
        
            # Find '🎯 Sprint Goals Status' heading_3
            if block_type == "heading3" and "sprint goals status" in content_lower:
                sprint_goals_status_heading_idx = idx
    
        # 5. Validate Action Items section exists
        if action_items_heading_idx is None:
            errors.append("[X] Action Items heading not found")
        else:
            checks_passed.append("[C] Action Items heading found")
    
        # 6. Validate Meeting Analytics section exists after Action Items
        if meeting_analytics_heading_idx is None:
            errors.append("[X] heading_2 '📊 Meeting Analytics' not found")
        else:
            checks_passed.append("[C] heading_2 '📊 Meeting Analytics' found")
    
        if meeting_analytics_heading_idx <= action_items_heading_idx:
            errors.append(f"[X] Meeting Analytics section (idx {meeting_analytics_heading_idx}) must appear  AFTER Action Items section (idx {action_items_heading_idx})")
        else:
            checks_passed.append(f"[C] Meeting Analytics section (idx {meeting_analytics_heading_idx}) must appear AFTER Action Items section (idx {action_items_heading_idx})")
    
        # 7. Validate divider appears before Meeting Analytics (after Action Items)
        if divider_before_analytics_idx is None:
            errors.append("[X] Divider not found between Action Items and Meeting Analytics")
        else:
            checks_passed.append("[C] Divider found between Action Items and Meeting Analytics")
    
        if divider_before_analytics_idx <= action_items_heading_idx:
            errors.append("[X] Divider should appear after Action Items section")
        else:
            checks_passed.append("[C] Divider should appear after Action Items section")
    
        if divider_before_analytics_idx >= meeting_analytics_heading_idx:
            errors.append("[X] Divider should appear before Meeting Analytics heading")
        else:
            checks_passed.append("[C] Divider should appear before Meeting Analytics heading")
    
        # 8. Validate Blue callout with '📈' icon and exact meeting stats
        callout_found = False
        callout_valid = False
        callout_idx = None
    
        for idx in range(meeting_analytics_heading_idx + 1, min(meeting_analytics_heading_idx + 10, len(page_blocks_sorted))):
            block = page_blocks_sorted[idx]
            if block.get("type") == "callout":
                callout_found = True
                callout_idx = idx
                props = block.get("properties", {})
                content = block.get("content", "")
                content_lower = content.lower() if content else ""
            
                bg_color = props.get("backgroundColor", "").lower()
                icon = props.get("icon", "")
            
                # Check for blue background
                if "blue" not in bg_color:
                    errors.append(f"[X] Callout should have Blue background, got '{props.get('backgroundColor')}'")
                else:
                    checks_passed.append(f"[C] Callout should have Blue background, got '{props.get('backgroundColor')}'")
            
                # Check for 📈 icon
                if icon != "📈":
                    errors.append(f"[X] Callout should have '📈' icon, got '{icon}'")
                else:
                    checks_passed.append(f"[C] Callout should have '📈' icon, got '{icon}'")
            
                # Check for exact meeting stats content
                required_stats = [
                    "meeting duration: 2 hours (9:00 am - 11:00 am)",
                    "total participants: 3",
                    "action items completion: 100%"
                ]
            
                for stat in required_stats:
                    if stat not in content_lower:
                        errors.append(f"[X] Callout missing required stat: '{stat}', got content: '{content}'")
                    else:
                        checks_passed.append(f"[C] Callout has required stat: '{stat}', got content: '{content}'")
            
                callout_valid = True
                break
            elif block.get("type") == "heading3":
                # Stop if we hit a heading_3 before finding the callout
                break
    
        if not callout_found:
            errors.append("[X] Blue callout with '📈' icon not found after Meeting Analytics heading")
        else:
            checks_passed.append("[C] Blue callout with '📈' icon found after Meeting Analytics heading")
    
        if not callout_valid:
            errors.append("[X] Callout validation failed")
        else:
            checks_passed.append("[C] Callout validation succeeded")
    
        # 9. Validate Participant Contributions section
        if participant_contributions_heading_idx is None:
            errors.append("[X] heading_3 '👥 Participant Contributions' not found")
        else:
            checks_passed.append("[C] heading_3 '👥 Participant Contributions' found")
    
        # Validate participant contributions bulleted list
        expected_participants = [
            ("alice chen (product)", "create wireframes for sharing modal"),
            ("bob martinez (engineering)", "set up drag-and-drop library"),
            ("carol williams (design)", "[none assigned]")
        ]
    
        participant_bullets = []
        for idx in range(participant_contributions_heading_idx + 1, len(page_blocks_sorted)):
            block = page_blocks_sorted[idx]
            if block.get("type") == "bulletedList":
                participant_bullets.append(block.get("content", "").lower())
            elif block.get("type") in ["heading2", "heading3", "divider"]:
                break
    
        if len(participant_bullets) < 3:
            errors.append(f"[X] Expected at least 3 participant contribution bullets, found {len(participant_bullets)}")
        else:
            checks_passed.append(f"[C] Found at least 3 participant contribution bullets ({len(participant_bullets)})")
    
        # Validate each participant entry
        for participant_name, action_item in expected_participants:
            found = False
            for bullet_content in participant_bullets:
                if participant_name in bullet_content and action_item in bullet_content:
                    found = True
                    break
            if not found:
                errors.append(f"[X] Participant entry not found: '{participant_name}: {action_item}'")
            else:
                checks_passed.append(f"[C] Participant entry found: '{participant_name}: {action_item}'")
    
        # 10. Validate Sprint Goals Status section
        if sprint_goals_status_heading_idx is None:
            errors.append("[X] heading_3 '🎯 Sprint Goals Status' not found")
        else:
            checks_passed.append("[C] heading_3 '🎯 Sprint Goals Status' found")
    
        # Validate sprint goals numbered list with checkmark emojis
        expected_goals = [
            "complete authentication flow redesign",
            "implement block drag-and-drop",
            "add page sharing permissions ui"
        ]
    
        goal_items = []
        for idx in range(sprint_goals_status_heading_idx + 1, len(page_blocks_sorted)):
            block = page_blocks_sorted[idx]
            if block.get("type") == "numberedList":
                goal_items.append(block.get("content", ""))
            elif block.get("type") in ["heading2", "heading3", "divider", "paragraph"]:
                # Stop at paragraph or next section
                if block.get("type") == "paragraph":
                    # Check if this might be the closing paragraph
                    pass
                break
    
        if len(goal_items) < 3:
            errors.append(f"[X] Expected 3 sprint goals in numbered list, found {len(goal_items)}")
        else:
            checks_passed.append(f"[C] Found 3 sprint goals in numbered list as expected")
    
        # Validate each goal has checkmark emoji and correct text
        for expected_goal in expected_goals:
            found = False
            for item_content in goal_items:
                item_lower = item_content.lower()
                # Check for checkmark emoji and goal text
                if "✅" in item_content and expected_goal in item_lower:
                    found = True
                    break
            if not found:
                errors.append(f"[X] Sprint goal not found with checkmark: '✅ {expected_goal}'")
            else:
                checks_passed.append(f"[C] Sprint goal found with checkmark: '✅ {expected_goal}'")
    
        # 11. Validate closing italic paragraph
        closing_paragraph_found = False
        expected_closing_text = "meeting productivity score: excellent (all action items completed)"
    
        # Look for paragraph after sprint goals
        for idx in range(sprint_goals_status_heading_idx + 1, len(page_blocks_sorted)):
            block = page_blocks_sorted[idx]
            if block.get("type") == "paragraph":
                content = block.get("content", "").lower()
                if expected_closing_text in content:
                    # Check for italic formatting (either via properties or markdown markers)
                    props = block.get("properties", {})
                    content_raw = block.get("content", "")
                
                    # Accept either italic property or *text* markdown style
                    if props.get("italic") or "*" in content_raw or "_" in content_raw:
                        closing_paragraph_found = True
                    else:
                        # Still accept if text matches, even without explicit italic formatting
                        closing_paragraph_found = True
                    break
    
        if not closing_paragraph_found:
            errors.append(f"[X] Closing paragraph with italic text '{expected_closing_text}' not found")
        else:
            checks_passed.append(f"[C] Closing paragraph with italic text '{expected_closing_text}' found")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

    # -----------------------------------------------------------------------------
    # Task: weekly-standup-time-estimates
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_weekly_standup_time_estimates(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate weekly standup time estimates section task.
    
    Success criteria:
    1. The heading_3 '⏰ Time Estimates' appears exactly after block-9-10 
       ('Waiting for design review on component Z') but before any following sections
    2. The heading_3 has bold styling
    3. A yellow callout with '⚡' icon contains exact text 
       'Track estimated vs actual time for better planning'
    4. Four unchecked todo blocks exist with exact texts and emoji prefixes:
       - '🕐 Feature Y implementation (Est: 16h)'
       - '📝 API documentation (Est: 8h)'
       - '🧪 Integration testing (Est: 12h)'
       - '🔍 Code review backlog (Est: 4h)'
    5. Final paragraph has 'Total estimated hours: 40' with '40' in bold
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    
    # 1. Find Weekly Standup Template page (page-9)
    try:
        standup_page = _find_page_by_title(final_state_backend, "Weekly Standup Template")
        if not standup_page:
            errors.append("[X] Weekly Standup Template page not found")
        else:
            checks_passed.append("[C] Weekly Standup Template page found")
    
        page_id = standup_page.get("_id")
        page_blocks = _get_blocks_for_page(final_state_backend, page_id)
    
        if not page_blocks:
            errors.append("[X] No blocks found on Weekly Standup Template page")
        else:
            checks_passed.append("[C] blocks found on Weekly Standup Template page")
    
        # Sort blocks by order to ensure correct sequence
        page_blocks_sorted = sorted(page_blocks, key=lambda b: b.get("order", 0))
    
        # 2. Find block-9-10 ('Waiting for design review on component Z') position
        block_9_10_idx = None
        time_estimates_heading_idx = None
        next_section_idx = None
    
        for idx, block in enumerate(page_blocks_sorted):
            block_id = block.get("_id", "")
            content = block.get("content", "").lower()
            block_type = block.get("type", "")
        
            # Find block-9-10 (the last unchecked todo 'Waiting for design review on component Z')
            if block_id == "block-9-10" or "waiting for design review on component z" in content:
                block_9_10_idx = idx
        
            # Find the time estimates heading
            if block_type == "heading3" and "time estimates" in content:
                time_estimates_heading_idx = idx
        
            # Find any following section heading (heading2 or heading3 that's not our new heading)
            if block_9_10_idx is not None and next_section_idx is None:
                if block_type in ["heading2", "heading3"] and idx > block_9_10_idx:
                    if "time estimates" not in content:
                        next_section_idx = idx
    
        if block_9_10_idx is None:
            errors.append("[X] block-9-10 ('Waiting for design review on component Z' todo) not found")
        else:
            checks_passed.append("[C] block-9-10 ('Waiting for design review on component Z' todo) found")
    
        # 3. Verify heading_3 '⏰ Time Estimates' exists after block-9-10
        if time_estimates_heading_idx is None:
            errors.append("[X] heading_3 '⏰ Time Estimates' not found")
        else:
            checks_passed.append("[C] heading_3 '⏰ Time Estimates' found")
    
        if time_estimates_heading_idx <= block_9_10_idx:
            errors.append(f"[X] '⏰ Time Estimates' heading must appear AFTER block-9-10 (found at index {time_estimates_heading_idx}, block-9-10 at {block_9_10_idx})")
        else:
            checks_passed.append(f"[C] '⏰ Time Estimates' heading must appear AFTER block-9-10 (found at index {time_estimates_heading_idx}, block-9-10 at {block_9_10_idx})")
    
        # Verify exact content and styling of the time estimates heading
        time_estimates_block = page_blocks_sorted[time_estimates_heading_idx]
        time_estimates_content = time_estimates_block.get("content", "")
    
        # Check for bold styling
        time_estimates_props = time_estimates_block.get("properties", {})
        has_bold = time_estimates_props.get("bold", False)
        # Also check if content contains bold markdown markers
        if not has_bold and "**" not in time_estimates_content and "__" not in time_estimates_content:
            # Still allow if the heading type itself implies styling
            pass  # Heading3 might implicitly have bold styling in some implementations
    
        # 4. Find and verify the yellow callout with ⚡ icon
        callout_found = False
        callout_idx = None
        expected_callout_text = "Track estimated vs actual time for better planning"
    
        for idx in range(time_estimates_heading_idx + 1, len(page_blocks_sorted)):
            block = page_blocks_sorted[idx]
            if block.get("type") == "callout":
                callout_content = block.get("content", "")
                callout_props = block.get("properties", {})
            
                # Check for yellow background
                bg_color = callout_props.get("backgroundColor", "").lower()
                has_yellow_bg = "yellow" in bg_color or bg_color == "yellow"
            
                # Check for ⚡ icon
                icon = callout_props.get("icon", "")
                has_lightning_icon = "⚡" in icon or icon == "⚡"
            
                # Check exact text content
                has_correct_text = expected_callout_text.lower() in callout_content.lower()
            
                if has_correct_text:
                    callout_found = True
                    callout_idx = idx
                
                    if not has_yellow_bg:
                        errors.append(f"[X] Callout should have yellow background, found: '{bg_color}'")
                    else:
                        checks_passed.append(f"[C] Callout should have yellow background, found: '{bg_color}'")
                
                    if not has_lightning_icon:
                        errors.append(f"[X] Callout should have '⚡' icon, found: '{icon}'")
                    else:
                        checks_passed.append(f"[C] Callout should have '⚡' icon, found: '{icon}'")
                
                    break
    
        if not callout_found:
            errors.append(f"[X] Yellow callout with exact text '{expected_callout_text}' not found")
        else:
            checks_passed.append(f"[C] Yellow callout with exact text '{expected_callout_text}' found")
    
        # 5. Verify the four required todo blocks exist after the callout
        required_todos = [
            "🕐 Feature Y implementation (Est: 16h)",
            "📝 API documentation (Est: 8h)",
            "🧪 Integration testing (Est: 12h)",
            "🔍 Code review backlog (Est: 4h)"
        ]
    
        # Look for todos after the callout
        found_todos = []
        search_start = callout_idx + 1 if callout_idx else time_estimates_heading_idx + 1
        search_end = next_section_idx if next_section_idx else len(page_blocks_sorted)
    
        for idx in range(search_start, search_end):
            block = page_blocks_sorted[idx]
            if block.get("type") == "todo":
                found_todos.append(block)
    
        if len(found_todos) < 4:
            errors.append(f"[X] Expected 4 todo blocks under '⏰ Time Estimates', found {len(found_todos)}")
        else:
            checks_passed.append(f"[C] Found 4 todo blocks under '⏰ Time Estimates' as expected")
    
        # Check that required todos are present with exact text
        found_todo_texts = [b.get("content", "") for b in found_todos]
    
        for required_todo in required_todos:
            found = False
            for found_text in found_todo_texts:
                # Check for emoji prefix and key content
                emoji = required_todo[0:2]  # Get the emoji (including potential variation selector)
                if emoji in found_text or required_todo.lower() in found_text.lower():
                    found = True
                    break
                # Also try flexible matching
                if required_todo.lower().replace(" ", "") in found_text.lower().replace(" ", ""):
                    found = True
                    break
            if not found:
                errors.append(f"[X] Required todo not found: '{required_todo}'")
            else:
                checks_passed.append(f"[C] Required todo found: '{required_todo}'")
    
        # 6. Verify all new todos are unchecked
        for todo_block in found_todos[:4]:  # Check first 4 todos (the new ones)
            properties = todo_block.get("properties", {})
            if properties.get("checked", False):
                errors.append(f"[X] New todo block should be unchecked: '{todo_block.get('content')}'")
            else:
                checks_passed.append(f"[C] New todo block should be unchecked: '{todo_block.get('content')}'")
    
        # 7. Verify the final paragraph with 'Total estimated hours: 40' and bold '40'
        total_paragraph_found = False
        expected_total_text = "Total estimated hours: 40"
    
        for idx in range(search_start, search_end):
            block = page_blocks_sorted[idx]
            if block.get("type") == "paragraph":
                content = block.get("content", "")
                content_lower = content.lower()
            
                if "total estimated hours" in content_lower and "40" in content:
                    total_paragraph_found = True
                
                    # Check if '40' is bold (either via properties or markdown markers)
                    props = block.get("properties", {})
                    has_bold_in_props = props.get("bold", False)
                    has_bold_markdown = "**40**" in content or "__40__" in content
                
                    # Also check for inline formatting in content (some implementations use this)
                    # Accept various bold formats
                    if not has_bold_in_props and not has_bold_markdown:
                        # Check if there's any indication of bold formatting around '40'
                        # Allow flexible matching for different markdown/formatting styles
                        if "*40*" in content or "_40_" in content:
                            has_bold_markdown = True
                
                    if not has_bold_in_props and not has_bold_markdown:
                        errors.append(f"[X] '40' in total paragraph should be bold formatted")
                    else:
                        checks_passed.append(f"[C] '40' in total paragraph should be bold formatted")
                
                    break
    
        if not total_paragraph_found:
            errors.append(f"[X] Paragraph with '{expected_total_text}' not found")
        else:
            checks_passed.append(f"[C] Paragraph with '{expected_total_text}' found")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

    # -----------------------------------------------------------------------------
    # Task: code-examples-reorganization
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_code_examples_reorganization(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Code Examples Repository reorganization task.
    
    Success criteria:
    1. Python Examples section appears BEFORE Javascript Examples section (swapped)
    2. New '🦀 Rust Examples' section is positioned exactly between Typescript and Bash sections
    3. Rust section has a code block with language 'rust' containing fibonacci implementation
    4. Rust section has a paragraph with 'Recursive Fibonacci implementation in Rust.'
    5. Green callout at the top (after heading1) with 💡 icon displays correct language count
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    
    # 1. Find 'Code Examples Repository' page
    try:
        code_examples_page = _find_page_by_title(final_state_backend, "Code Examples Repository")
        if not code_examples_page:
            errors.append("[X] Code Examples Repository page not found")
        else:
            checks_passed.append("[C] Code Examples Repository page found")
    
        page_id = code_examples_page.get("_id")
        page_blocks = _get_blocks_for_page(final_state_backend, page_id)
    
        if not page_blocks:
            errors.append("[X] No blocks found on Code Examples Repository page")
        else:
            checks_passed.append("[C] blocks found on Code Examples Repository page")
    
        # Sort blocks by order to ensure correct sequence
        page_blocks_sorted = sorted(page_blocks, key=lambda b: b.get("order", 0))
    
        # 2. Find the main heading_1 (should be first)
        main_heading_idx = None
        for idx, block in enumerate(page_blocks_sorted):
            if block.get("type") == "heading1":
                main_heading_idx = idx
                break
    
        if main_heading_idx is None:
            errors.append("[X] Main heading_1 not found on the page")
        else:
            checks_passed.append("[C] Main heading_1 found on the page")
    
        # 3. Find all heading2 blocks (language sections)
        heading2_blocks = []
        for idx, block in enumerate(page_blocks_sorted):
            if block.get("type") == "heading2":
                heading2_blocks.append((idx, block))
    
        if len(heading2_blocks) < 5:
            errors.append(f"[X] Expected at least 5 heading2 blocks (language sections), found {len(heading2_blocks)}")
        else:
            checks_passed.append(f"[C] Found at least 5 heading2 blocks (language sections) ({len(heading2_blocks)})")
    
        # Extract heading2 texts in order for validation
        heading2_texts_ordered = [b.get("content", "").lower() for idx, b in heading2_blocks]
    
        # 4. Verify Python Examples appears BEFORE Javascript Examples (swap check)
        python_idx = None
        javascript_idx = None
    
        for i, text in enumerate(heading2_texts_ordered):
            if "python" in text and "examples" in text:
                python_idx = i
            elif "javascript" in text and "examples" in text:
                javascript_idx = i
    
        if python_idx is None:
            errors.append("[X] Python Examples section (heading2) not found")
        else:
            checks_passed.append("[C] Python Examples section (heading2) found")
    
        if javascript_idx is None:
            errors.append("[X] Javascript Examples section (heading2) not found")
        else:
            checks_passed.append("[C] Javascript Examples section (heading2) found")
    
        if python_idx >= javascript_idx:
            errors.append(f"[X] Python Examples (position {python_idx}) should appear BEFORE Javascript Examples (position {javascript_idx}) - sections were not swapped correctly")
        else:
            checks_passed.append(f"[C] Python Examples (position {python_idx}) should appear BEFORE Javascript Examples (position {javascript_idx}) - sections were swapped correctly")
    
        # 5. Find Typescript, Rust, and Bash sections for ordering check
        typescript_idx = None
        rust_idx = None
        bash_idx = None
    
        for i, text in enumerate(heading2_texts_ordered):
            if "typescript" in text and "examples" in text:
                typescript_idx = i
            elif "rust" in text and "examples" in text:
                rust_idx = i
            elif "bash" in text and "examples" in text:
                bash_idx = i
    
        if typescript_idx is None:
            errors.append("[X] Typescript Examples section (heading2) not found")
        else:
            checks_passed.append("[C] Typescript Examples section (heading2) found")
    
        if rust_idx is None:
            errors.append("[X] '🦀 Rust Examples' section (heading2) not found - needs to be added")
        else:
            checks_passed.append("[C] '🦀 Rust Examples' section (heading2) found - needs to be added")
    
        if bash_idx is None:
            errors.append("[X] Bash Examples section (heading2) not found")
        else:
            checks_passed.append("[C] Bash Examples section (heading2) found")
    
        # 6. Verify Rust Examples is positioned between Typescript and Bash
        if not (typescript_idx < rust_idx < bash_idx):
            errors.append(f"[X] 🦀 Rust Examples section (position {rust_idx}) must be positioned  AFTER Typescript Examples (position {typescript_idx}) and  BEFORE Bash Examples (position {bash_idx})")
        else:
            checks_passed.append(f"[C] 🦀 Rust Examples section (position {rust_idx}) must be positioned AFTER Typescript Examples (position {typescript_idx}) and BEFORE Bash Examples (position {bash_idx})")
    
        # 7. Find the Rust section's code block and verify content
        rust_block_idx = heading2_blocks[rust_idx][0]
        # Find the next heading2 or end of page to define Rust section boundaries
        rust_section_end = len(page_blocks_sorted)
        if rust_idx + 1 < len(heading2_blocks):
            rust_section_end = heading2_blocks[rust_idx + 1][0]
    
        rust_code_block = None
        rust_description_paragraph = None
    
        for idx in range(rust_block_idx + 1, rust_section_end):
            block = page_blocks_sorted[idx]
            if block.get("type") == "code":
                rust_code_block = block
            elif block.get("type") == "paragraph":
                content = block.get("content", "").lower()
                if "fibonacci" in content and "rust" in content:
                    rust_description_paragraph = block
    
        if rust_code_block is None:
            errors.append("[X] Code block not found in '🦀 Rust Examples' section")
        else:
            checks_passed.append("[C] Code block found in '🦀 Rust Examples' section")
    
        # Verify code block has language property set to 'rust'
        rust_code_props = rust_code_block.get("properties", {})
        rust_language = rust_code_props.get("language", "").lower()
        if rust_language != "rust":
            errors.append(f"[X] Rust code block should have language property 'rust', found: '{rust_language}'")
        else:
            checks_passed.append(f"[C] Rust code block should have language property 'rust', found: '{rust_language}'")
    
        # Verify code block content contains fibonacci implementation
        rust_code_content = rust_code_block.get("content", "")
        fibonacci_keywords = ["fn fibonacci", "match n", "fibonacci(n - 1)", "fibonacci(n - 2)"]
        missing_keywords = [kw for kw in fibonacci_keywords if kw.lower() not in rust_code_content.lower()]
    
        if len(missing_keywords) > 1:  # Allow some flexibility
            errors.append(f"[X] Rust code block missing expected fibonacci implementation. Expected keywords like: {fibonacci_keywords}")
        else:
            checks_passed.append(f"[C] Rust code block has expected fibonacci implementation. Expected keywords like: {fibonacci_keywords}")
    
        # 9. Verify paragraph description exists
        if rust_description_paragraph is None:
            errors.append("[X] Paragraph with 'Recursive Fibonacci implementation in Rust.' not found in Rust section")
        else:
            checks_passed.append("[C] Paragraph with 'Recursive Fibonacci implementation in Rust.' found in Rust section")
    
        # 10. Verify green callout at the top (after heading1)
        green_callout_found = False
        green_callout_idx = None
        callout_language_count = None
        total_language_sections = len(heading2_blocks)
    
        # Look for callout between main heading and first heading2
        first_heading2_idx = heading2_blocks[0][0] if heading2_blocks else len(page_blocks_sorted)
    
        for idx in range(main_heading_idx + 1, first_heading2_idx):
            block = page_blocks_sorted[idx]
            if block.get("type") == "callout":
                props = block.get("properties", {})
                content = block.get("content", "")
                bg_color = props.get("backgroundColor", "").lower()
                icon = props.get("icon", "")
            
                # Check for green background
                has_green_bg = "green" in bg_color
            
                # Check for 💡 icon
                has_lightbulb_icon = "💡" in icon or icon == "💡"
            
                # Check content pattern: "This repository contains [X] programming languages"
                if "repository contains" in content.lower() and "programming languages" in content.lower():
                    green_callout_found = True
                    green_callout_idx = idx
                
                    if not has_green_bg:
                        errors.append(f"[X] Top callout should have green background, found: '{bg_color}'")
                    else:
                        checks_passed.append(f"[C] Top callout should have green background, found: '{bg_color}'")
                
                    if not has_lightbulb_icon:
                        errors.append(f"[X] Top callout should have '💡' icon, found: '{icon}'")
                    else:
                        checks_passed.append(f"[C] Top callout should have '💡' icon, found: '{icon}'")
                
                    # Extract the number from content
                    import re
                    numbers = re.findall(r'\d+', content)
                    if numbers:
                        callout_language_count = int(numbers[0])
                    break
    
        if not green_callout_found:
            errors.append("[X] Green callout with 💡 icon and text This repository contains [X] programming languages...  not found after main heading1")
        else:
            checks_passed.append("[C] Green callout with 💡 icon and text This repository contains [X] programming languages... found after main heading1")
    
        # 11. Verify the callout displays the correct language count
        if callout_language_count is None:
            errors.append("[X] Could not extract language count from callout text")
        else:
            checks_passed.append("[C] Could extract language count from callout text")
    
        if callout_language_count != total_language_sections:
            errors.append(f"[X] Callout displays {callout_language_count} languages but page has  {total_language_sections} language sections (heading2 blocks)")
        else:
            checks_passed.append(f"[C] Callout displays {callout_language_count} languages but page has {total_language_sections} language sections (heading2 blocks)")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

    # -----------------------------------------------------------------------------
    # Task: project-health-dashboard-2
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_project_health_dashboard_2(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate project health dashboard creation.
    
    Success criteria:
    1. 'Project Health Dashboard' page exists as child of 'Project Documentation'
    2. Page starts with heading_1 '🏥 Project Health Dashboard'
    3. heading_2 '📊 Documentation Coverage' with bulleted list of sub-pages and block counts
    4. heading_2 '🎯 Content Depth Analysis' with:
       - Deepest page hierarchy level
       - Pages with 10+ blocks listed
       - Pages needing content (<5 blocks) listed
    5. heading_2 '🏗️ Architecture Overview' with:
       - Frontend Architecture sub-page count
       - Total architecture pages count
    6. Callout at end with correct color based on documentation health percentage:
       - Red if <50% pages have 10+ blocks
       - Yellow if 50-75% pages have 10+ blocks
       - Green if >75% pages have 10+ blocks
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    
    # 1. Verify 'Project Documentation' exists
    try:
        project_doc = _find_page_by_title(final_state_backend, "Project Documentation")
        if not project_doc:
            errors.append("[X] Project Documentation page not found")
        else:
            checks_passed.append("[C] Project Documentation page found")
    
        # 2. Verify 'Project Health Dashboard' exists as child of Project Documentation
        dashboard = _find_page_by_title(final_state_backend, "Project Health Dashboard")
        if not dashboard:
            errors.append("[X] Project Health Dashboard page not found")
        else:
            checks_passed.append("[C] Project Health Dashboard page found")
    
        if not _check_page_is_child_of(project_doc, dashboard):
            errors.append("[X] Project Health Dashboard is not a child of Project Documentation")
        else:
            checks_passed.append("[C] Project Health Dashboard is a child of Project Documentation")
    
        # 3. Get all sub-pages of Project Documentation (excluding the dashboard itself)
        def get_all_descendants(page_id: str, exclude_id: str = None) -> List[Dict[str, Any]]:
            """Recursively get all descendant pages."""
            descendants = []
            children = _get_child_pages(final_state_backend, page_id)
            for child in children:
                child_id = child.get("_id")
                if exclude_id and child_id == exclude_id:
                    continue
                descendants.append(child)
                descendants.extend(get_all_descendants(child_id, exclude_id))
            return descendants
    
        dashboard_id = dashboard.get("_id")
        all_subpages = get_all_descendants(project_doc.get("_id"), exclude_id=dashboard_id)
    
        # Calculate block counts for each sub-page
        subpage_block_counts = {}
        for subpage in all_subpages:
            subpage_id = subpage.get("_id")
            subpage_title = subpage.get("title", "")
            blocks = _get_blocks_for_page(final_state_backend, subpage_id)
            subpage_block_counts[subpage_title] = len(blocks)
    
        # Calculate hierarchy depth
        def get_hierarchy_depth(page_id: str, current_depth: int = 1) -> int:
            """Calculate maximum hierarchy depth from a page."""
            children = _get_child_pages(final_state_backend, page_id)
            if not children:
                return current_depth
            max_child_depth = current_depth
            for child in children:
                child_id = child.get("_id")
                if child_id == dashboard_id:
                    continue
                child_depth = get_hierarchy_depth(child_id, current_depth + 1)
                max_child_depth = max(max_child_depth, child_depth)
            return max_child_depth
    
        expected_depth = get_hierarchy_depth(project_doc.get("_id"))
    
        # Pages with 10+ blocks and pages needing content (<5 blocks)
        pages_with_10_plus = [title for title, count in subpage_block_counts.items() if count >= 10]
        pages_needing_content = [title for title, count in subpage_block_counts.items() if count < 5]
    
        # Calculate documentation health percentage
        total_subpages = len(all_subpages)
        well_documented_count = len(pages_with_10_plus)
        health_percentage = (well_documented_count / total_subpages * 100) if total_subpages > 0 else 0
    
        # Determine expected callout color
        if health_percentage < 50:
            expected_color = "red"
            expected_status = "needs improvement"
        elif health_percentage <= 75:
            expected_color = "yellow"
            expected_status = "moderate"
        else:
            expected_color = "green"
            expected_status = "healthy"
    
        # Get Frontend Architecture sub-page count
        frontend_arch = _find_page_by_title(final_state_backend, "Frontend Architecture")
        frontend_arch_subpages = 0
        total_arch_pages = 0
    
        if frontend_arch:
            frontend_arch_children = get_all_descendants(frontend_arch.get("_id"))
            frontend_arch_subpages = len(frontend_arch_children)
            total_arch_pages = 1 + frontend_arch_subpages  # Include Frontend Architecture itself
    
        # Also check for Architecture page
        architecture_page = _find_page_by_title(final_state_backend, "Architecture")
        if architecture_page:
            arch_descendants = get_all_descendants(architecture_page.get("_id"))
            total_arch_pages = 1 + len(arch_descendants)
    
        # 4. Get blocks from the dashboard page
        dashboard_blocks = _get_blocks_for_page(final_state_backend, dashboard_id)
    
        if len(dashboard_blocks) < 8:  # Minimum expected blocks
            errors.append(f"[X] Project Health Dashboard has too few blocks ({len(dashboard_blocks)})")
        else:
            checks_passed.append(f"[C] Project Health Dashboard has too few blocks ({len(dashboard_blocks)})")
    
        # Sort blocks by order
        page_blocks_sorted = sorted(dashboard_blocks, key=lambda b: b.get("order", 0))
    
        block_idx = 0
    
        # 5. Validate heading_1 '🏥 Project Health Dashboard'
        if block_idx >= len(page_blocks_sorted):
            errors.append("[X] Missing heading1 block")
        else:
            checks_passed.append("[C] has heading1 block")
        if page_blocks_sorted[block_idx].get("type") != "heading1":
            errors.append(f"[X] Block {block_idx} should be heading1, got {page_blocks_sorted[block_idx].get('type')}")
        else:
            checks_passed.append(f"[C] Block {block_idx} should be heading1, got {page_blocks_sorted[block_idx].get('type')}")
        heading1_content = page_blocks_sorted[block_idx].get("content", "").lower()
        if "project health dashboard" not in heading1_content:
            errors.append("[X] heading1 should contain 'Project Health Dashboard'")
        else:
            checks_passed.append("[C] heading1 should contain 'Project Health Dashboard'")
        block_idx += 1
    
        # 6. Validate heading_2 '📊 Documentation Coverage'
        if block_idx >= len(page_blocks_sorted):
            errors.append("[X] Missing heading2 block for Documentation Coverage")
        else:
            checks_passed.append("[C] has heading2 block for Documentation Coverage")
        if page_blocks_sorted[block_idx].get("type") != "heading2":
            errors.append(f"[X] Block {block_idx} should be heading2, got {page_blocks_sorted[block_idx].get('type')}")
        else:
            checks_passed.append(f"[C] Block {block_idx} should be heading2, got {page_blocks_sorted[block_idx].get('type')}")
        if "documentation coverage" not in page_blocks_sorted[block_idx].get("content", "").lower():
            errors.append("[X] heading2 should contain 'Documentation Coverage'")
        else:
            checks_passed.append("[C] heading2 should contain 'Documentation Coverage'")
        block_idx += 1
    
        # 7. Validate sub-page listing with block counts
        # Collect all content from blocks in this section until next heading2
        coverage_content = ""
        coverage_block_idx = block_idx
        while coverage_block_idx < len(page_blocks_sorted):
            block = page_blocks_sorted[coverage_block_idx]
            if block.get("type") in ["heading2", "heading1"]:
                break
            content = block.get("content", "")
            coverage_content += content.lower() + " "
            coverage_block_idx += 1
    
        # Verify at least some sub-pages are listed with block counts
        subpages_found_in_coverage = 0
        for title, count in subpage_block_counts.items():
            title_lower = title.lower()
            # Check if page name and a number (block count) appear in coverage content
            if title_lower in coverage_content:
                # Also check for block count mention
                if str(count) in coverage_content or "block" in coverage_content:
                    subpages_found_in_coverage += 1
    
        if subpages_found_in_coverage < min(3, len(subpage_block_counts)):
            errors.append(f"[X] Documentation Coverage section should list sub-pages with block counts. Found {subpages_found_in_coverage} of {len(subpage_block_counts)} sub-pages")
        else:
            checks_passed.append(f"[C] Documentation Coverage section should list sub-pages with block counts. Found {subpages_found_in_coverage} of {len(subpage_block_counts)} sub-pages")
    
        block_idx = coverage_block_idx
    
        # 8. Validate heading_2 '🎯 Content Depth Analysis'
        content_depth_found = False
        for i in range(block_idx, len(page_blocks_sorted)):
            block = page_blocks_sorted[i]
            if block.get("type") == "heading2":
                if "content depth analysis" in block.get("content", "").lower():
                    content_depth_found = True
                    block_idx = i + 1
                    break
    
        if not content_depth_found:
            errors.append("[X] heading2 '🎯 Content Depth Analysis' not found")
        else:
            checks_passed.append("[C] heading2 '🎯 Content Depth Analysis' found")
    
        # Collect content from Content Depth Analysis section
        depth_content = ""
        depth_block_idx = block_idx
        while depth_block_idx < len(page_blocks_sorted):
            block = page_blocks_sorted[depth_block_idx]
            if block.get("type") in ["heading2", "heading1"]:
                break
            content = block.get("content", "")
            depth_content += content.lower() + " "
            depth_block_idx += 1
    
        # Verify hierarchy depth is mentioned
        if "hierarchy" not in depth_content and "level" not in depth_content and "depth" not in depth_content:
            errors.append("[X] Content Depth Analysis should mention hierarchy depth/levels")
        else:
            checks_passed.append("[C] Content Depth Analysis should mention hierarchy depth/levels")
    
        # Verify depth number appears
        if str(expected_depth) not in depth_content:
            # Be lenient - just check that some depth number is mentioned
            import re
            depth_numbers = re.findall(r'\d+', depth_content)
            if not depth_numbers:
                errors.append(f"[X] Content Depth Analysis should mention hierarchy depth (expected: {expected_depth} levels)")
            else:
                checks_passed.append(f"[C] Content Depth Analysis should mention hierarchy depth (expected: {expected_depth} levels)")
    
        # Verify 10+ blocks section
        if "10+" not in depth_content and "10 or more" not in depth_content.replace(" ", "") and "ten" not in depth_content:
            # Check if pages with 10+ blocks are at least mentioned
            pass  # Be lenient here
    
        # Verify pages needing content section
        if "need" not in depth_content and "<5" not in depth_content and "fewer than 5" not in depth_content:
            pass  # Be lenient
    
        block_idx = depth_block_idx
    
        # 9. Validate heading_2 '🏗️ Architecture Overview'
        arch_overview_found = False
        for i in range(block_idx, len(page_blocks_sorted)):
            block = page_blocks_sorted[i]
            if block.get("type") == "heading2":
                if "architecture overview" in block.get("content", "").lower():
                    arch_overview_found = True
                    block_idx = i + 1
                    break
    
        if not arch_overview_found:
            errors.append("[X] heading2 '🏗️ Architecture Overview' not found")
        else:
            checks_passed.append("[C] heading2 '🏗️ Architecture Overview' found")
    
        # Collect content from Architecture Overview section
        arch_content = ""
        arch_block_idx = block_idx
        while arch_block_idx < len(page_blocks_sorted):
            block = page_blocks_sorted[arch_block_idx]
            if block.get("type") in ["heading2", "heading1", "callout"]:
                break
            content = block.get("content", "")
            arch_content += content.lower() + " "
            arch_block_idx += 1
    
        # Verify Frontend Architecture is mentioned
        if "frontend architecture" not in arch_content:
            errors.append("[X] Architecture Overview should mention 'Frontend Architecture'")
        else:
            checks_passed.append("[C] Architecture Overview should mention 'Frontend Architecture'")
    
        block_idx = arch_block_idx
    
        # 10. Validate final callout with correct color and health status
        callout_found = False
        callout_color = None
        callout_content = ""
    
        for i in range(len(page_blocks_sorted) - 1, -1, -1):  # Search from end
            block = page_blocks_sorted[i]
            if block.get("type") == "callout":
                callout_found = True
                props = block.get("properties", {})
                callout_color = props.get("backgroundColor", "").lower()
                callout_content = block.get("content", "").lower()
                break
    
        if not callout_found:
            errors.append("[X] Final callout with documentation health status not found")
        else:
            checks_passed.append("[C] Final callout with documentation health status found")
    
        # Validate callout color matches health percentage
        if expected_color not in callout_color:
            errors.append(f"[X] Callout should have {expected_color} background (health: {health_percentage:.1f}%), got '{callout_color}'")
        else:
            checks_passed.append(f"[C] Callout should have {expected_color} background (health: {health_percentage:.1f}%), got '{callout_color}'")
    
        # Validate callout mentions health/status
        if "health" not in callout_content and "status" not in callout_content:
            errors.append("[X] Callout should contain 'Documentation health' or status indicator")
        else:
            checks_passed.append("[C] Callout should contain 'Documentation health' or status indicator")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

    # -----------------------------------------------------------------------------
    # Task: prd-security-compliance
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_prd_security_compliance(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate PRD Security Compliance section insertion."""
    errors: list[str] = []
    checks_passed: list[str] = []

    
    
    # 1. Find the 'Comprehensive Product Requirements Document' page (page-47)
    try:
        prd_page = _find_page_by_title(final_state_backend, "Comprehensive Product Requirements Document")
        if not prd_page:
            errors.append("[X] Comprehensive Product Requirements Document page not found")
        else:
            checks_passed.append("[C] Comprehensive Product Requirements Document page found")
    
        prd_page_id = prd_page.get("_id")
    
        # 2. Get all blocks for the PRD page and sort by order
        page_blocks = _get_blocks_for_page(final_state_backend, prd_page_id)
        if not page_blocks:
            errors.append("[X] No blocks found on PRD page")
        else:
            checks_passed.append("[C] blocks found on PRD page")
    
        page_blocks_sorted = sorted(page_blocks, key=lambda b: b.get("order", 0))
    
        # 3. Find the reference blocks for position validation
        tech_req_part2_block = None
        tech_req_part3_block = None
        security_compliance_block = None
    
        for block in page_blocks_sorted:
            content = block.get("content", "").strip()
            block_type = block.get("type", "")
        
            if block_type == "heading3":
                if content == "Technical Requirements - Part 2":
                    tech_req_part2_block = block
                elif content == "Technical Requirements - Part 3":
                    tech_req_part3_block = block
                elif content == "Technical Requirements - Security Compliance":
                    security_compliance_block = block
    
        # Validate Technical Requirements - Part 2 exists
        if not tech_req_part2_block:
            errors.append("[X] Technical Requirements - Part 2 heading not found")
        else:
            checks_passed.append("[C] Technical Requirements - Part 2 heading found")
    
        # Validate Technical Requirements - Part 3 exists  
        if not tech_req_part3_block:
            errors.append("[X] Technical Requirements - Part 3 heading not found")
        else:
            checks_passed.append("[C] Technical Requirements - Part 3 heading found")
    
        # 4. Validate new heading3 'Technical Requirements - Security Compliance' exists
        if not security_compliance_block:
            errors.append("[X] Technical Requirements - Security Compliance heading_3 not found")
        else:
            checks_passed.append("[C] Technical Requirements - Security Compliance heading_3 found")
    
        # 5. Validate position: Security Compliance should be after Part 2 and before Part 3
        part2_order = tech_req_part2_block.get("order", 0)
        part3_order = tech_req_part3_block.get("order", 0)
        security_order = security_compliance_block.get("order", 0)
    
        if not (part2_order < security_order < part3_order):
            errors.append(f"[X] Security Compliance section not in correct position.  Part 2 order: {part2_order}, Security order: {security_order}, Part 3 order: {part3_order}.  Expected: Part 2 < Security < Part 3")
        else:
            checks_passed.append(f"[C] Security Compliance section in correct position. Part 2 order: {part2_order}, Security order: {security_order}, Part 3 order: {part3_order}. Expected: Part 2 < Security < Part 3")
    
        # 6. Find blocks immediately following the Security Compliance heading
        security_block_idx = None
        for idx, block in enumerate(page_blocks_sorted):
            if block.get("_id") == security_compliance_block.get("_id"):
                security_block_idx = idx
                break
    
        if security_block_idx is None:
            errors.append("[X] Could not locate Security Compliance block position")
        else:
            checks_passed.append("[C] Could locate Security Compliance block position")
    
        # 7. Check for two identical paragraphs with the required text
        expected_paragraph_text = "Security compliance is paramount for our technical implementation. All data must be encrypted at rest and in transit."
    
        paragraphs_found = []
        for idx in range(security_block_idx + 1, min(security_block_idx + 10, len(page_blocks_sorted))):
            block = page_blocks_sorted[idx]
            if block.get("type") == "paragraph":
                content = block.get("content", "").strip()
                if expected_paragraph_text.lower() in content.lower():
                    paragraphs_found.append(block)
            elif block.get("type") in ["heading1", "heading2", "heading3"]:
                break  # Stop at next heading
    
        if len(paragraphs_found) < 2:
            errors.append(f"[X] Expected 2 identical paragraphs with security compliance text, found {len(paragraphs_found)}")
        else:
            checks_passed.append(f"[C] Found 2 identical paragraphs with security compliance text as expected")
    
        # 8. Check for bulleted list with exactly 3 items
        expected_bullets = [
            "SOC 2 Type II certification required",
            "GDPR compliance for EU operations",
            "Regular penetration testing quarterly"
        ]
    
        bullet_items_found = []
        for idx in range(security_block_idx + 1, min(security_block_idx + 15, len(page_blocks_sorted))):
            block = page_blocks_sorted[idx]
            if block.get("type") == "bulletedList":
                content = block.get("content", "").strip()
                bullet_items_found.append(content)
            elif block.get("type") in ["heading1", "heading2", "heading3"]:
                break  # Stop at next heading
    
        if len(bullet_items_found) != 3:
            errors.append(f"[X] Expected exactly 3 bulleted list items, found {len(bullet_items_found)}")
        else:
            checks_passed.append(f"[C] Expected exactly 3 bulleted list items, found {len(bullet_items_found)}")
    
        # Verify bullet content (case-insensitive, flexible matching)
        for expected in expected_bullets:
            found = False
            for bullet in bullet_items_found:
                if expected.lower() in bullet.lower():
                    found = True
                    break
            if not found:
                errors.append(f"[X] Missing bulleted list item: '{expected}'")
            else:
                checks_passed.append(f"[C] has bulleted list item: '{expected}'")
    
        # 9. Count all heading3 blocks on the page
        heading3_count = sum(1 for b in page_blocks_sorted if b.get("type") == "heading3")
    
        # 10. Validate final paragraph with italic text and correct count
        # Find the last paragraph on the page
        last_paragraph = None
        for block in reversed(page_blocks_sorted):
            if block.get("type") == "paragraph":
                last_paragraph = block
                break
    
        if not last_paragraph:
            errors.append("[X] No final paragraph found at the end of the document")
        else:
            checks_passed.append("[C] final paragraph found at the end of the document")
    
        last_paragraph_content = last_paragraph.get("content", "").lower()
    
        # Check for the expected text pattern
        if "document contains" not in last_paragraph_content:
            errors.append("[X] Final paragraph should contain 'Document contains [X] detailed subsections...'")
        else:
            checks_passed.append("[C] Final paragraph should contain 'Document contains [X] detailed subsections...'")
    
        if "detailed subsections" not in last_paragraph_content and "subsections" not in last_paragraph_content:
            errors.append("[X] Final paragraph should mention 'detailed subsections for comprehensive coverage'")
        else:
            checks_passed.append("[C] Final paragraph should mention 'detailed subsections for comprehensive coverage'")
    
        # Check for italic formatting
        last_paragraph_props = last_paragraph.get("properties", {})
        text_style = last_paragraph_props.get("textStyle", {})
        is_italic = text_style.get("italic", False)
    
        # Also check if content contains italic markers or formatting
        content_raw = last_paragraph.get("content", "")
        has_italic_markers = "*" in content_raw or "_" in content_raw or is_italic
    
        if not has_italic_markers and not is_italic:
            # Check for inline styles
            inline_styles = last_paragraph_props.get("inlineStyles", [])
            has_italic_inline = any(
                style.get("style", {}).get("italic", False) 
                for style in inline_styles if isinstance(style, dict)
            )
            if not has_italic_inline:
                errors.append("[X] Final paragraph should have italic formatting")
            else:
                checks_passed.append("[C] Final paragraph should have italic formatting")
    
        # Verify the count in the paragraph matches the actual heading3 count
        # Extract number from the paragraph
        import re
        numbers_in_text = re.findall(r'\d+', last_paragraph_content)
    
        if not numbers_in_text:
            errors.append(f"[X] Final paragraph should contain the count of heading3 blocks ({heading3_count})")
        else:
            checks_passed.append(f"[C] Final paragraph should contain the count of heading3 blocks ({heading3_count})")
    
        # Check if any extracted number matches the heading3 count
        found_correct_count = any(int(num) == heading3_count for num in numbers_in_text)
    
        if not found_correct_count:
            errors.append(f"[X] Final paragraph count mismatch. Expected {heading3_count} heading3 blocks, but paragraph contains numbers: {numbers_in_text}")
        else:
            checks_passed.append(f"[C] Final paragraph count mismatch. Expected {heading3_count} heading3 blocks, but paragraph contains numbers: {numbers_in_text}")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# =============================================================================
# Registry of all V2 Reward Functions
# =============================================================================
# -----------------------------------------------------------------------------
# Task: weekly-standup-week-statistics
# -----------------------------------------------------------------------------
def _validate_agent_weekly_standup_week_statistics(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate weekly standup week statistics section task.
    
    Success criteria:
    1. New section is inserted immediately after the first heading2 block (block-9-3 "What I did this week")
    2. heading3 '📊 Week Statistics' exists with exact emoji and text
    3. Purple callout with 📈 icon exists after the heading3
    4. Callout contains a bold paragraph 'Weekly Metrics Dashboard'
    5. Three sequential Light Gray callout blocks exist:
       - Column 1: 'Monday-Tuesday' with 'Tasks: 0'
       - Column 2: 'Wednesday-Thursday' with 'Tasks: 0'
       - Column 3: 'Friday' with 'Tasks: 0'
    6. Divider exists after the column callouts
    7. Italic paragraph with text 'Update task counts as the week progresses.' with yellow color
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    
    # 1. Find Weekly Standup Template page (page-9)
    try:
        standup_page = _find_page_by_title(final_state_backend, "Weekly Standup Template")
        if not standup_page:
            errors.append("[X] Weekly Standup Template page not found")
        else:
            checks_passed.append("[C] Weekly Standup Template page found")
    
        page_id = standup_page.get("_id")
        page_blocks = _get_blocks_for_page(final_state_backend, page_id)
    
        if not page_blocks:
            errors.append("[X] No blocks found on Weekly Standup Template page")
        else:
            checks_passed.append("[C] blocks found on Weekly Standup Template page")
    
        # Sort blocks by order to ensure correct sequence
        page_blocks_sorted = sorted(page_blocks, key=lambda b: b.get("order", 0))
    
        # 2. Find the first heading2 block
        first_heading2_idx = None
        for idx, block in enumerate(page_blocks_sorted):
            if block.get("type") == "heading2":
                first_heading2_idx = idx
                break
    
        if first_heading2_idx is None:
            errors.append("[X] No heading2 block found on Weekly Standup Template page")
        else:
            checks_passed.append("[C] heading2 block found on Weekly Standup Template page")
    
        first_heading2_content = page_blocks_sorted[first_heading2_idx].get("content", "")
    
        # 3. Find '📊 Week Statistics' heading3
        week_statistics_heading_idx = None
        for idx, block in enumerate(page_blocks_sorted):
            block_type = block.get("type", "")
            content = block.get("content", "")
        
            if block_type == "heading3" and "week statistics" in content.lower():
                week_statistics_heading_idx = idx
                break
    
        if week_statistics_heading_idx is None:
            errors.append("[X] heading3 '📊 Week Statistics' not found")
        else:
            checks_passed.append("[C] heading3 '📊 Week Statistics' found")
    
        # Verify heading3 contains exact emoji
        week_statistics_block = page_blocks_sorted[week_statistics_heading_idx]
        week_statistics_content = week_statistics_block.get("content", "")
    
        # 4. Verify insertion is immediately after first heading2 block
        if week_statistics_heading_idx <= first_heading2_idx:
            errors.append(f"[X] 📊 Week Statistics heading (idx {week_statistics_heading_idx}) must appear  AFTER first heading2 block (idx {first_heading2_idx}, content: {first_heading2_content})")
        else:
            checks_passed.append(f"[C] 📊 Week Statistics heading (idx {week_statistics_heading_idx}) must appear AFTER first heading2 block (idx {first_heading2_idx}, content: {first_heading2_content})")
    
        # Check that it's inserted before the next major section (second heading2 or the todo blocks after first heading2)
        # Find the block that was originally after the first heading2 (should be a todo)
        original_next_block_idx = None
        for idx in range(first_heading2_idx + 1, len(page_blocks_sorted)):
            block = page_blocks_sorted[idx]
            block_id = block.get("_id", "")
            # Original todo after "What I did this week" was block-9-4
            if block_id == "block-9-4" or (block.get("type") == "todo" and "completed feature x" in block.get("content", "").lower()):
                original_next_block_idx = idx
                break
    
        if original_next_block_idx and week_statistics_heading_idx >= original_next_block_idx:
            errors.append(f"[X] 📊 Week Statistics section must be inserted IMMEDIATELY after first heading2,  but appears after original content (idx {week_statistics_heading_idx} >= {original_next_block_idx})")
        else:
            checks_passed.append(f"[C] 📊 Week Statistics section must be inserted IMMEDIATELY after first heading2, but appears after original content (idx {week_statistics_heading_idx} >= {original_next_block_idx})")
    
        # 5. Find Purple callout with 📈 icon after the heading3
        purple_callout_idx = None
        purple_callout_block = None
    
        for idx in range(week_statistics_heading_idx + 1, min(week_statistics_heading_idx + 10, len(page_blocks_sorted))):
            block = page_blocks_sorted[idx]
            if block.get("type") == "callout":
                props = block.get("properties", {})
                bg_color = props.get("backgroundColor", "").lower()
                icon = props.get("icon", "")
            
                if "purple" in bg_color and icon == "📈":
                    purple_callout_idx = idx
                    purple_callout_block = block
                    break
    
        if purple_callout_idx is None:
            errors.append("[X] Purple callout with '📈' icon not found after '📊 Week Statistics' heading")
        else:
            checks_passed.append("[C] Purple callout with '📈' icon found after '📊 Week Statistics' heading")
    
        # 6. Verify callout contains bold paragraph 'Weekly Metrics Dashboard'
        callout_content = purple_callout_block.get("content", "")
        if "weekly metrics dashboard" not in callout_content.lower():
            errors.append(f"[X] Purple callout should contain 'Weekly Metrics Dashboard', got: '{callout_content}'")
        else:
            checks_passed.append(f"[C] Purple callout should contain 'Weekly Metrics Dashboard', got: '{callout_content}'")
    
        # Check for bold formatting (either in properties or markdown syntax)
        callout_props = purple_callout_block.get("properties", {})
        is_bold = callout_props.get("bold", False)
        has_bold_markers = "**" in callout_content or "<b>" in callout_content or "<strong>" in callout_content
    
        if not is_bold and not has_bold_markers:
            # Be lenient - just check if 'Weekly Metrics Dashboard' text exists
            pass  # Allow without explicit bold check
    
        # 7. Find exactly 3 Light Gray callout blocks (column callouts)
        column_callouts = []
        expected_columns = [
            ("monday-tuesday", "tasks: 0"),
            ("wednesday-thursday", "tasks: 0"),
            ("friday", "tasks: 0")
        ]
    
        for idx in range(purple_callout_idx + 1, min(purple_callout_idx + 15, len(page_blocks_sorted))):
            block = page_blocks_sorted[idx]
            if block.get("type") == "callout":
                props = block.get("properties", {})
                bg_color = props.get("backgroundColor", "").lower()
            
                # Check for Light Gray background (could be 'light_gray', 'gray', 'light gray', etc.)
                if "gray" in bg_color or "grey" in bg_color:
                    column_callouts.append((idx, block))
            elif block.get("type") == "divider":
                # Stop when we hit the divider
                break
    
        if len(column_callouts) < 3:
            errors.append(f"[X] Expected 3 Light Gray callout blocks for columns, found {len(column_callouts)}")
        else:
            checks_passed.append(f"[C] Found 3 Light Gray callout blocks for columns as expected")
    
        # Validate each column callout has correct content
        for i, (col_idx, col_block) in enumerate(column_callouts[:3]):
            col_content = col_block.get("content", "").lower()
            expected_title, expected_tasks = expected_columns[i]
        
            if expected_title not in col_content:
                errors.append(f"[X] Column {i+1} callout should contain '{expected_title}', got: '{col_block.get('content')}'")
            else:
                checks_passed.append(f"[C] Column {i+1} callout should contain '{expected_title}', got: '{col_block.get('content')}'")
        
            if expected_tasks not in col_content:
                errors.append(f"[X] Column {i+1} callout should contain '{expected_tasks}', got: '{col_block.get('content')}'")
            else:
                checks_passed.append(f"[C] Column {i+1} callout should contain '{expected_tasks}', got: '{col_block.get('content')}'")
    
        # 8. Find divider after the column callouts
        divider_idx = None
        last_column_idx = column_callouts[2][0] if len(column_callouts) >= 3 else purple_callout_idx + 4
    
        for idx in range(last_column_idx + 1, min(last_column_idx + 5, len(page_blocks_sorted))):
            block = page_blocks_sorted[idx]
            if block.get("type") == "divider":
                divider_idx = idx
                break
    
        if divider_idx is None:
            errors.append("[X] Divider not found after the column callouts")
        else:
            checks_passed.append("[C] Divider found after the column callouts")
    
        # 9. Find italic paragraph with yellow color after divider
        final_paragraph_found = False
        final_paragraph_valid = False
    
        for idx in range(divider_idx + 1, min(divider_idx + 3, len(page_blocks_sorted))):
            block = page_blocks_sorted[idx]
            if block.get("type") == "paragraph":
                content = block.get("content", "")
                content_lower = content.lower()
            
                # Check for exact text
                if "update task counts as the week progresses" not in content_lower:
                    errors.append(f"[X] Final paragraph should contain 'Update task counts as the week progresses.', got: '{content}'")
                else:
                    checks_passed.append(f"[C] Final paragraph should contain 'Update task counts as the week progresses.', got: '{content}'")
            
                final_paragraph_found = True
                props = block.get("properties", {})
            
                # Check for italic formatting
                is_italic = props.get("italic", False)
                has_italic_markers = "*" in content or "_" in content or "<i>" in content or "<em>" in content
            
                if not is_italic and not has_italic_markers:
                    errors.append(f"[X] Final paragraph should have italic formatting, got properties: {props}")
                else:
                    checks_passed.append(f"[C] Final paragraph should have italic formatting, got properties: {props}")
            
                # Check for yellow color
                color = props.get("color", "").lower()
                bg_color = props.get("backgroundColor", "").lower()
            
                if "yellow" not in color and "yellow" not in bg_color:
                    errors.append(f"[X] Final paragraph should have yellow color, got color: '{props.get('color')}', backgroundColor: '{props.get('backgroundColor')}'")
                else:
                    checks_passed.append(f"[C] Final paragraph should have yellow color, got color: '{props.get('color')}', backgroundColor: '{props.get('backgroundColor')}'")
            
                final_paragraph_valid = True
                break
    
        if not final_paragraph_found:
            errors.append("[X] Final paragraph with 'Update task counts as the week progresses.' not found after divider")
        else:
            checks_passed.append("[C] Final paragraph with 'Update task counts as the week progresses.' found after divider")
    
        if not final_paragraph_valid:
            errors.append("[X] Final paragraph validation failed")
        else:
            checks_passed.append("[C] Final paragraph validation succeeded")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

    # -----------------------------------------------------------------------------
    # Task: weekly-standup-next-week-plans
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_weekly_standup_next_week_plans(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate weekly standup next week plans task.
    
    Success criteria:
    1. heading_2 'What I plan for next week' appears AFTER the 'What I did this week' section 
       and its to-do items but BEFORE 'What I plan to do next week' section
    2. Exactly 4 unchecked todo blocks with specified emojis and text exist under the new heading:
       - '🎯 Define API endpoints for new feature'
       - '📝 Write technical documentation'
       - '🔍 Code review for authentication module'
       - '🚀 Deploy beta version to staging'
    3. Divider and quote block with exact text 'Progress is progress, no matter how small.' 
       appear at the very end of the page
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    
    # 1. Find Weekly Standup Template page (page-9)
    try:
        standup_page = _find_page_by_title(final_state_backend, "Weekly Standup Template")
        if not standup_page:
            errors.append("[X] Weekly Standup Template page not found")
        else:
            checks_passed.append("[C] Weekly Standup Template page found")
    
        page_id = standup_page.get("_id")
        page_blocks = _get_blocks_for_page(final_state_backend, page_id)
    
        if not page_blocks:
            errors.append("[X] No blocks found on Weekly Standup Template page")
        else:
            checks_passed.append("[C] blocks found on Weekly Standup Template page")
    
        # Sort blocks by order to ensure correct sequence
        page_blocks_sorted = sorted(page_blocks, key=lambda b: b.get("order", 0))
    
        # 2. Find the 'What I did this week' heading and its last todo
        what_i_did_heading_idx = None
        what_i_plan_to_do_heading_idx = None
        new_what_i_plan_heading_idx = None
        last_what_i_did_todo_idx = None
    
        for idx, block in enumerate(page_blocks_sorted):
            block_type = block.get("type", "")
            content = block.get("content", "").lower()
        
            if block_type == "heading2" and "what i did this week" in content:
                what_i_did_heading_idx = idx
        
            if block_type == "heading2" and "what i plan to do next week" in content:
                what_i_plan_to_do_heading_idx = idx
        
            if block_type == "heading2" and "what i plan for next week" in content:
                new_what_i_plan_heading_idx = idx
    
        if what_i_did_heading_idx is None:
            errors.append("[X] 'What I did this week' heading not found")
        else:
            checks_passed.append("[C] 'What I did this week' heading found")
    
        if what_i_plan_to_do_heading_idx is None:
            errors.append("[X] 'What I plan to do next week' heading not found")
        else:
            checks_passed.append("[C] 'What I plan to do next week' heading found")
    
        # 3. Find the last todo under 'What I did this week' (before new heading or 'What I plan to do next week')
        # Use the new heading as the boundary if it exists, otherwise use the original boundary
        end_idx = new_what_i_plan_heading_idx if new_what_i_plan_heading_idx is not None else what_i_plan_to_do_heading_idx
        for idx in range(what_i_did_heading_idx + 1, end_idx):
            block = page_blocks_sorted[idx]
            if block.get("type") == "todo":
                last_what_i_did_todo_idx = idx
    
        if last_what_i_did_todo_idx is None:
            errors.append("[X] No todo blocks found under 'What I did this week' section")
        else:
            checks_passed.append("[C] todo blocks found under 'What I did this week' section")
    
        # 4. Verify new heading_2 'What I plan for next week' exists
        if new_what_i_plan_heading_idx is None:
            errors.append("[X] heading_2 'What I plan for next week' not found")
        else:
            checks_passed.append("[C] heading_2 'What I plan for next week' found")
    
        # Verify it appears AFTER the last todo of 'What I did this week' section
        if new_what_i_plan_heading_idx <= last_what_i_did_todo_idx:
            errors.append(f"[X] 'What I plan for next week' heading must appear AFTER the last todo of 'What I did this week' section (found at idx {new_what_i_plan_heading_idx}, last todo at {last_what_i_did_todo_idx})")
        else:
            checks_passed.append(f"[C] 'What I plan for next week' heading must appear AFTER the last todo of 'What I did this week' section (found at idx {new_what_i_plan_heading_idx}, last todo at {last_what_i_did_todo_idx})")
    
        # Verify it appears BEFORE 'What I plan to do next week' section
        if new_what_i_plan_heading_idx >= what_i_plan_to_do_heading_idx:
            errors.append(f"[X] 'What I plan for next week' heading must appear BEFORE 'What I plan to do next week' section (found at idx {new_what_i_plan_heading_idx}, 'What I plan to do' at {what_i_plan_to_do_heading_idx})")
        else:
            checks_passed.append(f"[C] 'What I plan for next week' heading must appear BEFORE 'What I plan to do next week' section (found at idx {new_what_i_plan_heading_idx}, 'What I plan to do' at {what_i_plan_to_do_heading_idx})")
    
        # 5. Verify exactly 4 unchecked todos with specified text exist after the new heading
        required_todos = [
            "🎯 Define API endpoints for new feature",
            "📝 Write technical documentation",
            "🔍 Code review for authentication module",
            "🚀 Deploy beta version to staging"
        ]
    
        # Find todos between new heading and the next section
        found_todos = []
        for idx in range(new_what_i_plan_heading_idx + 1, what_i_plan_to_do_heading_idx):
            block = page_blocks_sorted[idx]
            if block.get("type") == "todo":
                todo_content = block.get("content", "")
                todo_checked = block.get("properties", {}).get("checked", False)
                found_todos.append({"content": todo_content, "checked": todo_checked, "idx": idx})
    
        # Check exact count
        if len(found_todos) != 4:
            errors.append(f"[X] Expected exactly 4 todo blocks under 'What I plan for next week', found {len(found_todos)}")
        else:
            checks_passed.append(f"[C] Expected exactly 4 todo blocks under 'What I plan for next week', found {len(found_todos)}")
    
        # Check all are unchecked
        for todo in found_todos:
            if todo["checked"]:
                errors.append(f"[X] Todo '{todo['content']}' should be unchecked")
            else:
                checks_passed.append(f"[C] Todo '{todo['content']}' should be unchecked")
    
        # Check exact content matches (case-insensitive for text, exact for emojis)
        found_contents = [t["content"] for t in found_todos]
        for required_todo in required_todos:
            found_match = False
            for found_content in found_contents:
                # Check emoji is present and text matches
                emoji = required_todo[0]
                text = required_todo[2:].strip()  # Text after emoji and space
                if emoji in found_content and text.lower() in found_content.lower():
                    found_match = True
                    break
            if not found_match:
                errors.append(f"[X] Required todo '{required_todo}' not found. Found: {found_contents}")
            else:
                checks_passed.append(f"[C] Required todo '{required_todo}' found. Found: {found_contents}")
    
        # 6. Verify divider and quote block at end of page
        # Get the last few blocks
        if len(page_blocks_sorted) < 2:
            errors.append("[X] Page does not have enough blocks for divider and quote at end")
        else:
            checks_passed.append("[C] Page has enough blocks for divider and quote at end")
    
        # Find divider and quote at end
        divider_found = False
        quote_found = False
        quote_content_valid = False
    
        # Look for divider followed by quote in the last several blocks
        for idx in range(len(page_blocks_sorted) - 1, -1, -1):
            block = page_blocks_sorted[idx]
            block_type = block.get("type", "")
        
            if block_type == "quote":
                quote_content = block.get("content", "")
                expected_quote = "Progress is progress, no matter how small."
                if expected_quote.lower() in quote_content.lower():
                    quote_found = True
                    quote_content_valid = True
                    # Now check that there's a divider before this quote
                    for div_idx in range(idx - 1, -1, -1):
                        prev_block = page_blocks_sorted[div_idx]
                        if prev_block.get("type") == "divider":
                            divider_found = True
                            break
                        # Allow for the divider to be right before quote
                        elif prev_block.get("type") not in ["divider"]:
                            # Check if we're looking at the block right before quote
                            if div_idx == idx - 1 and prev_block.get("type") != "divider":
                                break
                break
    
        if not quote_found:
            errors.append("[X] Quote block not found at end of page")
        else:
            checks_passed.append("[C] Quote block found at end of page")
    
        if not quote_content_valid:
            errors.append("[X] Quote block should contain 'Progress is progress, no matter how small.'")
        else:
            checks_passed.append("[C] Quote block should contain 'Progress is progress, matter how small.'")
    
        if not divider_found:
            errors.append("[X] Divider not found before quote block at end of page")
        else:
            checks_passed.append("[C] Divider found before quote block at end of page")
    
        # Verify quote is at or near end of page (last 3 blocks)
        last_block = page_blocks_sorted[-1]
        second_to_last = page_blocks_sorted[-2] if len(page_blocks_sorted) > 1 else None
        third_to_last = page_blocks_sorted[-3] if len(page_blocks_sorted) > 2 else None
    
        quote_at_end = (
            last_block.get("type") == "quote" or 
            (second_to_last and second_to_last.get("type") == "quote") or
            (third_to_last and third_to_last.get("type") == "quote")
        )
    
        if not quote_at_end:
            errors.append("[X] Quote block should be at the very end of the page")
        else:
            checks_passed.append("[C] Quote block should be at the very end of the page")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_agent_product_localization_tracker(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate product localization tracker page creation."""
    errors: list[str] = []
    checks_passed: list[str] = []

    
    
    # 1. Find the Product Localization Tracker page
    try:
        tracker_page = _find_page_by_title(final_state_backend, "🌏 Product Localization Tracker")
        if not tracker_page:
            # Try without emoji
            tracker_page = _find_page_by_title(final_state_backend, "Product Localization Tracker")
        if not tracker_page:
            errors.append("[X] Product Localization Tracker page not found")
        else:
            checks_passed.append("[C] Product Localization Tracker page found")
    
        # 2. Get all blocks for this page
        page_blocks = _get_blocks_for_page(final_state_backend, tracker_page.get("_id"))
        if not page_blocks:
            errors.append("[X] No blocks found in Product Localization Tracker page")
        else:
            checks_passed.append("[C] blocks found in Product Localization Tracker page")
    
        # Sort blocks by order if available
        page_blocks_sorted = sorted(page_blocks, key=lambda b: b.get("order", 0))
    
        # Define expected market data
        markets = [
            {"heading": "🇺🇸 United States (EN-US)", "checked": 10, "unchecked": 0},
            {"heading": "🇪🇸 Spain (ES-ES)", "checked": 7, "unchecked": 3},
            {"heading": "🇯🇵 Japan (JA-JP)", "checked": 5, "unchecked": 5},
            {"heading": "🇩🇪 Germany (DE-DE)", "checked": 8, "unchecked": 2},
            {"heading": "🇫🇷 France (FR-FR)", "checked": 6, "unchecked": 4},
        ]
    
        block_idx = 0
    
        # 3. Check heading1: '🌏 Global Product Localization Status'
        if block_idx >= len(page_blocks_sorted):
            errors.append("[X] Missing heading1 block")
        else:
            checks_passed.append("[C] has heading1 block")
        h1_block = page_blocks_sorted[block_idx]
        if h1_block.get("type") != "heading1":
            errors.append(f"[X] First block should be heading1, got {h1_block.get('type')}")
        else:
            checks_passed.append(f"[C] First block should be heading1, got {h1_block.get('type')}")
        h1_content = h1_block.get("content", "").lower()
        if "global product localization status" not in h1_content:
            errors.append(f"[X] heading1 should contain 'Global Product Localization Status', got '{h1_block.get('content')}'")
        else:
            checks_passed.append(f"[C] heading1 should contain 'Global Product Localization Status', got '{h1_block.get('content')}'")
        block_idx += 1
    
        # 4. Check callout block (yellow_background, 🌍 icon)
        if block_idx >= len(page_blocks_sorted):
            errors.append("[X] Missing callout block")
        else:
            checks_passed.append("[C] has callout block")
        callout_block = page_blocks_sorted[block_idx]
        if callout_block.get("type") != "callout":
            errors.append(f"[X] Block {block_idx} should be callout, got {callout_block.get('type')}")
        else:
            checks_passed.append(f"[C] Block {block_idx} should be callout, got {callout_block.get('type')}")
    
        callout_props = callout_block.get("properties", {})
        bg_color = callout_props.get("backgroundColor", "")
        if "yellow" not in bg_color.lower():
            errors.append(f"[X] Callout should have yellow background, got {bg_color}")
        else:
            checks_passed.append(f"[C] Callout should have yellow background, got {bg_color}")
        if callout_props.get("icon") != "🌍":
            errors.append(f"[X] Callout should have 🌍 icon, got {callout_props.get('icon')}")
        else:
            checks_passed.append(f"[C] Callout should have 🌍 icon, got {callout_props.get('icon')}")
    
        callout_content = callout_block.get("content", "").lower()
        if "tracking localization progress across 5 key markets" not in callout_content:
            errors.append(f"[X] Callout should contain 'Tracking localization progress across 5 key markets', got '{callout_block.get('content')}'")
        else:
            checks_passed.append(f"[C] Callout should contain 'Tracking localization progress across 5 key markets', got '{callout_block.get('content')}'")
        block_idx += 1
    
        # 5. Check heading2: '🎯 Target Markets'
        if block_idx >= len(page_blocks_sorted):
            errors.append("[X] Missing heading2 for Target Markets")
        else:
            checks_passed.append("[C] has heading2 for Target Markets")
        h2_markets = page_blocks_sorted[block_idx]
        if h2_markets.get("type") != "heading2":
            errors.append(f"[X] Block {block_idx} should be heading2 for Target Markets, got {h2_markets.get('type')}")
        else:
            checks_passed.append(f"[C] Block {block_idx} should be heading2 for Target Markets, got {h2_markets.get('type')}")
        if "target markets" not in h2_markets.get("content", "").lower():
            errors.append(f"[X] heading2 should contain 'Target Markets', got '{h2_markets.get('content')}'")
        else:
            checks_passed.append(f"[C] heading2 should contain 'Target Markets', got '{h2_markets.get('content')}'")
        block_idx += 1
    
        # 6. Validate each market section (5 markets, each with heading3 + 10 todos)
        for market in markets:
            expected_heading = market["heading"]
            expected_checked = market["checked"]
            expected_unchecked = market["unchecked"]
        
            # Check heading3 for market
            if block_idx >= len(page_blocks_sorted):
                errors.append(f"[X] Missing heading3 for market '{expected_heading}'")
            else:
                checks_passed.append(f"[C] has heading3 for market '{expected_heading}'")
            market_heading = page_blocks_sorted[block_idx]
            if market_heading.get("type") != "heading3":
                errors.append(f"[X] Expected heading3 for '{expected_heading}', got {market_heading.get('type')}")
            else:
                checks_passed.append(f"[C] Expected heading3 for '{expected_heading}', got {market_heading.get('type')}")
        
            market_content = market_heading.get("content", "")
            # Check for key parts of the heading (flag and locale code)
            heading_lower = expected_heading.lower()
            content_lower = market_content.lower()
        
            # Extract the country name and locale code for flexible matching
            # e.g., "United States (EN-US)" -> check for "united states" and "en-us"
            if "united states" in heading_lower:
                if "united states" not in content_lower or "en-us" not in content_lower:
                    errors.append(f"[X] Market heading should contain 'United States' and 'EN-US', got '{market_content}'")
            elif "spain" in heading_lower:
                if "spain" not in content_lower or "es-es" not in content_lower:
                    errors.append(f"[X] Market heading should contain 'Spain' and 'ES-ES', got '{market_content}'")
            elif "japan" in heading_lower:
                if "japan" not in content_lower or "ja-jp" not in content_lower:
                    errors.append(f"[X] Market heading should contain 'Japan' and 'JA-JP', got '{market_content}'")
            elif "germany" in heading_lower:
                if "germany" not in content_lower or "de-de" not in content_lower:
                    errors.append(f"[X] Market heading should contain 'Germany' and 'DE-DE', got '{market_content}'")
            elif "france" in heading_lower:
                if "france" not in content_lower or "fr-fr" not in content_lower:
                    errors.append(f"[X] Market heading should contain 'France' and 'FR-FR', got '{market_content}'")
                else:
                    checks_passed.append(f"[C] Market heading should contain 'France' and 'FR-FR', got '{market_content}'")
        
            block_idx += 1
        
            # Count todos for this market (should be exactly 10)
            market_todos = []
            while block_idx < len(page_blocks_sorted) and page_blocks_sorted[block_idx].get("type") == "todo":
                market_todos.append(page_blocks_sorted[block_idx])
                block_idx += 1
        
            if len(market_todos) != 10:
                errors.append(f"[X] Market '{expected_heading}' should have exactly 10 todo blocks, found {len(market_todos)}")
            else:
                checks_passed.append(f"[C] Market '{expected_heading}' should have exactly 10 todo blocks, found {len(market_todos)}")
        
            # Count checked and unchecked
            checked_count = sum(1 for t in market_todos if t.get("properties", {}).get("checked"))
            unchecked_count = len(market_todos) - checked_count
        
            if checked_count != expected_checked:
                errors.append(f"[X] Market '{expected_heading}' should have {expected_checked} checked todos, found {checked_count}")
            else:
                checks_passed.append(f"[C] Market '{expected_heading}' should have {expected_checked} checked todos, found {checked_count}")
            if unchecked_count != expected_unchecked:
                errors.append(f"[X] Market '{expected_heading}' should have {expected_unchecked} unchecked todos, found {unchecked_count}")
            else:
                checks_passed.append(f"[C] Market '{expected_heading}' should have {expected_unchecked} unchecked todos, found {unchecked_count}")
    
        # 7. Check heading2: '📊 Localization Summary'
        if block_idx >= len(page_blocks_sorted):
            errors.append("[X] Missing heading2 for Localization Summary")
        else:
            checks_passed.append("[C] has heading2 for Localization Summary")
        h2_summary = page_blocks_sorted[block_idx]
        if h2_summary.get("type") != "heading2":
            errors.append(f"[X] Expected heading2 for Localization Summary, got {h2_summary.get('type')}")
        else:
            checks_passed.append(f"[C] Expected heading2 for Localization Summary, got {h2_summary.get('type')}")
        if "localization summary" not in h2_summary.get("content", "").lower():
            errors.append(f"[X] heading2 should contain 'Localization Summary', got '{h2_summary.get('content')}'")
        else:
            checks_passed.append(f"[C] heading2 should contain 'Localization Summary', got '{h2_summary.get('content')}'")
        block_idx += 1
    
        # 8. Check numbered list items (5 items)
        expected_summaries = [
            ("36/50", "72%"),
            ("fully localized", "1 market"),
            ("in progress", "4 markets"),
            ("highest completion", "united states", "100%"),
            ("lowest completion", "japan", "50%"),
        ]
    
        numbered_list_items = []
        while block_idx < len(page_blocks_sorted) and page_blocks_sorted[block_idx].get("type") == "numberedList":
            numbered_list_items.append(page_blocks_sorted[block_idx])
            block_idx += 1
    
        if len(numbered_list_items) != 5:
            errors.append(f"[X] Expected 5 numbered list items in summary, found {len(numbered_list_items)}")
        else:
            checks_passed.append(f"[C] Found 5 numbered list items in summary as expected")
    
        # Validate summary content
        summary_contents = [item.get("content", "").lower() for item in numbered_list_items]
    
        # Check first item: Overall Progress: 36/50 (72%)
        if "36/50" not in summary_contents[0] or "72%" not in summary_contents[0]:
            errors.append(f"[X] First summary item should contain '36/50' and '72%', got '{numbered_list_items[0].get('content')}'")
        else:
            checks_passed.append(f"[C] First summary item should contain '36/50' and '72%', got '{numbered_list_items[0].get('content')}'")
    
        # Check second item: Fully Localized: 1 market
        if "fully localized" not in summary_contents[1] or "1 market" not in summary_contents[1]:
            errors.append(f"[X] Second summary item should contain 'Fully Localized' and '1 market', got '{numbered_list_items[1].get('content')}'")
        else:
            checks_passed.append(f"[C] Second summary item should contain 'Fully Localized' and '1 market', got '{numbered_list_items[1].get('content')}'")
    
        # Check third item: In Progress: 4 markets
        if "in progress" not in summary_contents[2] or "4 markets" not in summary_contents[2]:
            errors.append(f"[X] Third summary item should contain 'In Progress' and '4 markets', got '{numbered_list_items[2].get('content')}'")
        else:
            checks_passed.append(f"[C] Third summary item should contain 'In Progress' and '4 markets', got '{numbered_list_items[2].get('content')}'")
    
        # Check fourth item: Highest Completion: United States (100%)
        if "highest completion" not in summary_contents[3] or "united states" not in summary_contents[3] or "100%" not in summary_contents[3]:
            errors.append(f"[X] Fourth summary item should contain 'Highest Completion', 'United States' and '100%', got '{numbered_list_items[3].get('content')}'")
        else:
            checks_passed.append(f"[C] Fourth summary item should contain 'Highest Completion', 'United States' and '100%', got '{numbered_list_items[3].get('content')}'")
    
        # Check fifth item: Lowest Completion: Japan (50%)
        if "lowest completion" not in summary_contents[4] or "japan" not in summary_contents[4] or "50%" not in summary_contents[4]:
            errors.append(f"[X] Fifth summary item should contain 'Lowest Completion', 'Japan' and '50%', got '{numbered_list_items[4].get('content')}'")
        else:
            checks_passed.append(f"[C] Fifth summary item should contain 'Lowest Completion', 'Japan' and '50%', got '{numbered_list_items[4].get('content')}'")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

    # -----------------------------------------------------------------------------
    # Task: code-examples-performance-patterns
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_code_examples_performance_patterns(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Performance Optimization Patterns section added to Code Examples Repository.
    
    Success criteria:
    1. New section is positioned exactly after 'SQL Examples' section
    2. Heading hierarchy is exact (h2 for main section, h3 for subsection)
    3. Code block contains exact memoization code with javascript language tag
    4. Callout has Green background with info emoji and exact text
    5. Final count paragraph accurately reflects total code blocks and languages
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    
    # 1. Find 'Code Examples Repository' page
    try:
        code_examples_page = _find_page_by_title(final_state_backend, "Code Examples Repository")
        if not code_examples_page:
            errors.append("[X] Code Examples Repository page not found")
        else:
            checks_passed.append("[C] Code Examples Repository page found")
    
        page_id = code_examples_page.get("_id")
        page_blocks = _get_blocks_for_page(final_state_backend, page_id)
    
        if not page_blocks:
            errors.append("[X] No blocks found on Code Examples Repository page")
        else:
            checks_passed.append("[C] blocks found on Code Examples Repository page")
    
        # Sort blocks by order
        page_blocks_sorted = sorted(page_blocks, key=lambda b: b.get("order", 0))
    
        # 2. Find 'Sql Examples' heading_2 section
        sql_examples_idx = None
        for idx, block in enumerate(page_blocks_sorted):
            if block.get("type") == "heading2":
                content = block.get("content", "").lower()
                if "sql examples" in content or content == "sql examples":
                    sql_examples_idx = idx
                    break
    
        if sql_examples_idx is None:
            errors.append("[X] SQL Examples heading_2 section not found")
        else:
            checks_passed.append("[C] SQL Examples heading_2 section found")
    
        # 3. Find where SQL section ends (next heading_2 or end of section content)
        sql_section_end_idx = sql_examples_idx + 1
        for idx in range(sql_examples_idx + 1, len(page_blocks_sorted)):
            block = page_blocks_sorted[idx]
            block_type = block.get("type", "")
            # SQL section ends when we hit the next heading_2 or the new Performance section
            if block_type == "heading2":
                sql_section_end_idx = idx
                break
    
        # 4. Check if Performance Optimization Patterns heading_2 exists after SQL section
        perf_section_idx = None
        for idx in range(sql_section_end_idx, len(page_blocks_sorted)):
            block = page_blocks_sorted[idx]
            if block.get("type") == "heading2":
                content = block.get("content", "")
                if "performance optimization patterns" in content.lower():
                    perf_section_idx = idx
                    break
    
        if perf_section_idx is None:
            errors.append("[X] Performance Optimization Patterns heading_2 not found after SQL Examples section")
        else:
            checks_passed.append("[C] Performance Optimization Patterns heading_2 found after SQL Examples section")
    
        # 5. Verify the section is positioned correctly (right after SQL Examples ends)
        # The new section should come before what was originally after SQL (like Go Examples)
        if perf_section_idx != sql_section_end_idx:
            # Check if there's a Go Examples or other section between SQL and Performance
            for idx in range(sql_section_end_idx, perf_section_idx):
                block = page_blocks_sorted[idx]
                if block.get("type") == "heading2":
                    other_heading = block.get("content", "").lower()
                    if "go examples" in other_heading or "rust examples" in other_heading:
                        errors.append(f"[X] Performance section must be immediately after SQL Examples, found '{block.get('content')}' in between")
                    else:
                        checks_passed.append(f"[C] Performance section must be immediately after SQL Examples, found '{block.get('content')}' in between")
    
        # 6. Verify paragraph 'Critical patterns for production-grade applications' follows the heading
        next_idx = perf_section_idx + 1
        if next_idx >= len(page_blocks_sorted):
            errors.append("[X] Missing paragraph after Performance Optimization Patterns heading")
        else:
            checks_passed.append("[C] has paragraph after Performance Optimization Patterns heading")
    
        intro_para = page_blocks_sorted[next_idx]
        if intro_para.get("type") != "paragraph":
            errors.append(f"[X] Expected paragraph after Performance heading, got {intro_para.get('type')}")
        else:
            checks_passed.append(f"[C] Expected paragraph after Performance heading, got {intro_para.get('type')}")
    
        intro_content = intro_para.get("content", "")
        if "critical patterns for production-grade applications" not in intro_content.lower():
            errors.append(f"[X] Paragraph should contain 'Critical patterns for production-grade applications', got '{intro_content}'")
        else:
            checks_passed.append(f"[C] Paragraph should contain 'Critical patterns for production-grade applications', got '{intro_content}'")
    
        # 7. Verify heading_3 '🚀 Caching Strategy' follows
        next_idx += 1
        if next_idx >= len(page_blocks_sorted):
            errors.append("[X] Missing heading_3 for Caching Strategy")
        else:
            checks_passed.append("[C] has heading_3 for Caching Strategy")
    
        caching_heading = page_blocks_sorted[next_idx]
        if caching_heading.get("type") != "heading3":
            errors.append(f"[X] Expected heading_3 for Caching Strategy, got {caching_heading.get('type')}")
        else:
            checks_passed.append(f"[C] Expected heading_3 for Caching Strategy, got {caching_heading.get('type')}")
    
        caching_content = caching_heading.get("content", "")
        if "caching strategy" not in caching_content.lower():
            errors.append(f"[X] heading_3 should contain 'Caching Strategy', got '{caching_content}'")
        else:
            checks_passed.append(f"[C] heading_3 should contain 'Caching Strategy', got '{caching_content}'")
    
        # 8. Verify code block with memoization pattern follows
        next_idx += 1
        if next_idx >= len(page_blocks_sorted):
            errors.append("[X] Missing code block for memoization pattern")
        else:
            checks_passed.append("[C] has code block for memoization pattern")
    
        code_block = page_blocks_sorted[next_idx]
        if code_block.get("type") != "code":
            errors.append(f"[X] Expected code block after Caching Strategy heading, got {code_block.get('type')}")
        else:
            checks_passed.append(f"[C] Expected code block after Caching Strategy heading, got {code_block.get('type')}")
    
        code_props = code_block.get("properties", {})
        code_language = code_props.get("language", "").lower()
        if code_language != "javascript":
            errors.append(f"[X] Code block should have language 'javascript', got '{code_language}'")
        else:
            checks_passed.append(f"[C] Code block should have language 'javascript', got '{code_language}'")
    
        code_content = code_block.get("content", "")
        # Check for key parts of the memoization code
        required_code_parts = [
            "const cache = new Map()",
            "const memoize",
            "JSON.stringify(args)",
            "cache.has(key)",
            "cache.get(key)",
            "cache.set(key, result)",
        ]
    
        for part in required_code_parts:
            if part.lower() not in code_content.lower():
                errors.append(f"[X] Code block missing required part: '{part}'")
            else:
                checks_passed.append(f"[C] Code block has required part: '{part}'")
    
        # 9. Verify Green callout with info text follows
        next_idx += 1
        if next_idx >= len(page_blocks_sorted):
            errors.append("[X] Missing callout block after code")
        else:
            checks_passed.append("[C] has callout block after code")
    
        callout_block = page_blocks_sorted[next_idx]
        if callout_block.get("type") != "callout":
            errors.append(f"[X] Expected callout block after code, got {callout_block.get('type')}")
        else:
            checks_passed.append(f"[C] Expected callout block after code, got {callout_block.get('type')}")
    
        callout_props = callout_block.get("properties", {})
        bg_color = callout_props.get("backgroundColor", "").lower()
        if "green" not in bg_color:
            errors.append(f"[X] Callout should have Green background, got '{callout_props.get('backgroundColor')}'")
        else:
            checks_passed.append(f"[C] Callout should have Green background, got '{callout_props.get('backgroundColor')}'")
    
        callout_content = callout_block.get("content", "")
        expected_callout_text = "this pattern reduces redundant calculations by up to 80% in recursive algorithms"
        if expected_callout_text not in callout_content.lower():
            errors.append(f"[X] Callout should contain '{expected_callout_text}', got '{callout_content}'")
        else:
            checks_passed.append(f"[C] Callout should contain '{expected_callout_text}', got '{callout_content}'")
    
        # 10. Verify divider follows the callout
        next_idx += 1
        if next_idx >= len(page_blocks_sorted):
            errors.append("[X] Missing divider after callout")
        else:
            checks_passed.append("[C] has divider after callout")
    
        divider_block = page_blocks_sorted[next_idx]
        if divider_block.get("type") != "divider":
            errors.append(f"[X] Expected divider after callout, got {divider_block.get('type')}")
        else:
            checks_passed.append(f"[C] Expected divider after callout, got {divider_block.get('type')}")
    
        # 11. Verify italic paragraph with code count follows
        next_idx += 1
        if next_idx >= len(page_blocks_sorted):
            errors.append("[X] Missing paragraph with code count after divider")
        else:
            checks_passed.append("[C] has paragraph with code count after divider")
    
        count_para = page_blocks_sorted[next_idx]
        if count_para.get("type") != "paragraph":
            errors.append(f"[X] Expected paragraph with code count after divider, got {count_para.get('type')}")
        else:
            checks_passed.append(f"[C] Expected paragraph with code count after divider, got {count_para.get('type')}")
    
        count_content = count_para.get("content", "").lower()
        if "this page now contains" not in count_content:
            errors.append(f"[X] Count paragraph should contain 'This page now contains', got '{count_para.get('content')}'")
        else:
            checks_passed.append(f"[C] Count paragraph should contain 'This page now contains', got '{count_para.get('content')}'")
        if "code examples" not in count_content:
            errors.append(f"[X] Count paragraph should mention 'code examples', got '{count_para.get('content')}'")
        else:
            checks_passed.append(f"[C] Count paragraph should mention 'code examples', got '{count_para.get('content')}'")
        if "programming languages" not in count_content:
            errors.append(f"[X] Count paragraph should mention 'programming languages', got '{count_para.get('content')}'")
        else:
            checks_passed.append(f"[C] Count paragraph should mention 'programming languages', got '{count_para.get('content')}'")
    
        # 12. Count all code blocks on the page to verify accuracy
        code_blocks = [b for b in page_blocks_sorted if b.get("type") == "code"]
        total_code_blocks = len(code_blocks)
    
        # Get unique programming languages
        languages = set()
        for cb in code_blocks:
            lang = cb.get("properties", {}).get("language", "").lower()
            if lang:
                languages.add(lang)
        total_languages = len(languages)
    
        # Verify the count in the paragraph matches
        # Expected: 9 code blocks across 8 languages (after adding the new javascript memoization)
        if str(total_code_blocks) not in count_para.get("content", ""):
            errors.append(f"[X] Count paragraph should mention {total_code_blocks} code examples, got '{count_para.get('content')}'")
        else:
            checks_passed.append(f"[C] Count paragraph should mention {total_code_blocks} code examples, got '{count_para.get('content')}'")
    
        if str(total_languages) not in count_para.get("content", ""):
            errors.append(f"[X] Count paragraph should mention {total_languages} programming languages, got '{count_para.get('content')}'")
        else:
            checks_passed.append(f"[C] Count paragraph should mention {total_languages} programming languages, got '{count_para.get('content')}'")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

    # -----------------------------------------------------------------------------
    # Task: code-review-standards
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_code_review_standards(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Code Review Standards section insertion on Project Guidelines page.
    
    Success criteria:
    1. Find the 'Project Guidelines & Best Practices' page (page-21)
    2. New heading_3 '🎯 Code Review Standards' exists
    3. The heading is positioned AFTER the '📝 Note: Update the changelog...' callout
    4. The heading is positioned BEFORE any '🔒 Security' callout
    5. Three callout blocks follow immediately after the heading in exact order:
       - Green background, ✅ icon, 'Required: All PRs must have at least 2 approvals'
       - Blue background, 🔍 icon, 'Best Practice: Include unit tests for all new functions'
       - Orange background, ⏰ icon, 'Timeline: Reviews should be completed within 24 hours'
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    
    # 1. Find the 'Project Guidelines & Best Practices' page
    try:
        guidelines_page = _find_page_by_title(final_state_backend, "Project Guidelines & Best Practices")
        if not guidelines_page:
            errors.append("[X] Project Guidelines & Best Practices page not found")
        else:
            checks_passed.append("[C] Project Guidelines & Best Practices page found")
    
        page_id = guidelines_page.get("_id")
    
        # 2. Get all blocks for the page and sort by order
        page_blocks = _get_blocks_for_page(final_state_backend, page_id)
        if not page_blocks:
            errors.append("[X] No blocks found on Project Guidelines & Best Practices page")
        else:
            checks_passed.append("[C] blocks found on Project Guidelines & Best Practices page")
    
        page_blocks_sorted = sorted(page_blocks, key=lambda b: b.get("order", 0))
    
        # 3. Find reference blocks and the new heading
        note_callout_block = None
        security_callout_block = None
        code_review_heading = None
    
        for block in page_blocks_sorted:
            content = block.get("content", "").strip()
            block_type = block.get("type", "")
            properties = block.get("properties", {})
            icon = properties.get("icon", "")
        
            # Find the Note callout
            if block_type == "callout" and "📝" in icon and "Update the changelog for all user-facing changes" in content:
                if note_callout_block is None:  # Take the first occurrence
                    note_callout_block = block
        
            # Find the Security callout (first one after note)
            if block_type == "callout" and "🔒" in icon and "Security" in content:
                if note_callout_block is not None and security_callout_block is None:
                    if block.get("order", 0) > note_callout_block.get("order", 0):
                        security_callout_block = block
        
            # Find the Code Review Standards heading
            if block_type == "heading3" and "🎯 Code Review Standards" in content:
                code_review_heading = block
    
        # 4. Validate the Note callout exists
        if not note_callout_block:
            errors.append("[X] Note callout with '📝 Note: Update the changelog for all user-facing changes.' not found")
        else:
            checks_passed.append("[C] Note callout with '📝 Note: Update the changelog for all user-facing changes.' found")
    
        # 5. Validate the Code Review Standards heading exists
        if not code_review_heading:
            errors.append("[X] heading_3 with '🎯 Code Review Standards' not found")
        else:
            checks_passed.append("[C] heading_3 with '🎯 Code Review Standards' found")
    
        # 6. Validate position: Code Review heading should be after Note callout
        note_order = note_callout_block.get("order", 0)
        heading_order = code_review_heading.get("order", 0)
    
        if heading_order <= note_order:
            errors.append(f"[X] Code Review Standards heading is not after the Note callout.  Note order: {note_order}, Heading order: {heading_order}")
        else:
            checks_passed.append(f"[C] Code Review Standards heading is after the Note callout. Note order: {note_order}, Heading order: {heading_order}")
    
        # 7. Validate position: Code Review heading should be before Security callout (if exists)
        if security_callout_block:
            security_order = security_callout_block.get("order", 0)
            if heading_order >= security_order:
                errors.append(f"[X] Code Review Standards heading is not before the Security callout.  Heading order: {heading_order}, Security order: {security_order}")
            else:
                checks_passed.append(f"[C] Code Review Standards heading is before the Security callout. Heading order: {heading_order}, Security order: {security_order}")
    
        # 8. Find the index of the Code Review heading in sorted blocks
        heading_idx = None
        for idx, block in enumerate(page_blocks_sorted):
            if block.get("_id") == code_review_heading.get("_id"):
                heading_idx = idx
                break
    
        if heading_idx is None:
            errors.append("[X] Could not locate Code Review Standards heading position")
        else:
            checks_passed.append("[C] Could locate Code Review Standards heading position")
    
        # 9. Validate the three callout blocks following the heading
        expected_callouts = [
            {
                "backgroundColor": "green_background",
                "icon": "✅",
                "text": "Required: All PRs must have at least 2 approvals"
            },
            {
                "backgroundColor": "blue_background",
                "icon": "🔍",
                "text": "Best Practice: Include unit tests for all new functions"
            },
            {
                "backgroundColor": "orange_background",
                "icon": "⏰",
                "text": "Timeline: Reviews should be completed within 24 hours"
            }
        ]
    
        # Check for the three callouts after the heading
        found_callouts = []
        for idx in range(heading_idx + 1, min(heading_idx + 6, len(page_blocks_sorted))):
            block = page_blocks_sorted[idx]
            if block.get("type") == "callout":
                found_callouts.append(block)
                if len(found_callouts) == 3:
                    break
            elif block.get("type") in ["heading1", "heading2", "heading3"]:
                # Stop if we hit another heading before finding all callouts
                break
    
        if len(found_callouts) != 3:
            errors.append(f"[X] Expected exactly 3 callout blocks after the Code Review Standards heading, found {len(found_callouts)}")
        else:
            checks_passed.append(f"[C] Expected exactly 3 callout blocks after the Code Review Standards heading, found {len(found_callouts)}")
    
        # Validate each callout in order
        for i, (expected, actual) in enumerate(zip(expected_callouts, found_callouts)):
            actual_content = actual.get("content", "").strip()
            actual_props = actual.get("properties", {})
            actual_bg = actual_props.get("backgroundColor", "")
            actual_icon = actual_props.get("icon", "")
        
            # Validate background color
            if actual_bg != expected["backgroundColor"]:
                errors.append(f"[X] Callout {i+1} has wrong background color.  Expected: {expected[backgroundColor]}, Got: {actual_bg}")
            else:
                checks_passed.append(f"[C] Callout {i+1} has wrong background color. Expected: {expected[backgroundColor]}, Got: {actual_bg}")
        
            # Validate icon
            if expected["icon"] not in actual_icon:
                errors.append(f"[X] Callout {i+1} has wrong icon.  Expected: {expected[icon]}, Got: {actual_icon}")
            else:
                checks_passed.append(f"[C] Callout {i+1} has wrong icon. Expected: {expected[icon]}, Got: {actual_icon}")
        
            # Validate text content (case-insensitive, but check exact text is present)
            if expected["text"].lower() not in actual_content.lower():
                errors.append(f"[X] Callout {i+1} has wrong text.  Expected to contain: {expected[text]}, Got: {actual_content}")
            else:
                checks_passed.append(f"[C] Callout {i+1} has wrong text. Expected to contain: {expected[text]}, Got: {actual_content}")
    
        # 10. Verify the callouts are in correct sequence (by order property)
        callout_orders = [c.get("order", 0) for c in found_callouts]
        if callout_orders != sorted(callout_orders):
            errors.append(f"[X] Callout blocks are not in the correct sequential order. Orders: {callout_orders}")
        else:
            checks_passed.append(f"[C] Callout blocks are in the correct sequential order. Orders: {callout_orders}")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

    # -----------------------------------------------------------------------------
    # Task: engineering-wiki-toc
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_engineering_wiki_toc(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Table of Contents section on Engineering Wiki page.
    
    Success criteria:
    1. TOC must be positioned after the main heading_1 but before any existing content
    2. heading_2 '📖 Table of Contents' exists as first section after title
    3. Yellow callout with '🔍' icon containing 'Quick navigation to all wiki sections'
    4. Numbered list with each heading_2 block and accurate counts:
       - Format: '[NUMBER]. [HEADING TEXT] - [PARAGRAPH COUNT] paragraphs, [LIST COUNT] lists'
    5. Divider after the numbered list
    6. Italic paragraph with 'Total sections: [X], Total content blocks: [Y]'
    
    Expected structure based on Engineering Wiki page:
    - Tech Stack section: 0 paragraphs, 1 list (bulletedList group)
    - Development Setup section: 1 paragraph, 1 list (numberedList group)
    - Total: 2 sections, 8 content blocks (or counted by grouping)
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    
    # 1. Find 'Engineering Wiki' page
    try:
        wiki_page = _find_page_by_title(final_state_backend, "Engineering Wiki")
        if not wiki_page:
            errors.append("[X] Engineering Wiki page not found")
        else:
            checks_passed.append("[C] Engineering Wiki page found")
    
        page_id = wiki_page.get("_id")
        page_blocks = _get_blocks_for_page(final_state_backend, page_id)
    
        if not page_blocks:
            errors.append("[X] No blocks found on Engineering Wiki page")
        else:
            checks_passed.append("[C] blocks found on Engineering Wiki page")
    
        # Sort blocks by order
        page_blocks_sorted = sorted(page_blocks, key=lambda b: b.get("order", 0))
    
        # 2. Find the main heading_1 (should be first)
        main_heading_idx = None
        for idx, block in enumerate(page_blocks_sorted):
            if block.get("type") == "heading1":
                main_heading_idx = idx
                break
    
        if main_heading_idx is None:
            errors.append("[X] Main heading_1 not found on the page")
        else:
            checks_passed.append("[C] Main heading_1 found on the page")
    
        # 3. Find the TOC heading_2 '📖 Table of Contents'
        toc_heading_idx = None
        for idx, block in enumerate(page_blocks_sorted):
            if block.get("type") == "heading2":
                content = block.get("content", "")
                if "table of contents" in content.lower() and "📖" in content:
                    toc_heading_idx = idx
                    break
    
        if toc_heading_idx is None:
            errors.append("[X] heading_2 '📖 Table of Contents' not found")
        else:
            checks_passed.append("[C] heading_2 '📖 Table of Contents' found")
    
        # 4. Verify TOC heading is immediately after main heading_1
        if toc_heading_idx <= main_heading_idx:
            errors.append(f"[X] TOC heading (idx {toc_heading_idx}) must be after main heading_1 (idx {main_heading_idx})")
        else:
            checks_passed.append(f"[C] TOC heading (idx {toc_heading_idx}) must be after main heading_1 (idx {main_heading_idx})")
    
        # Check that TOC is the first heading_2 after the main heading
        for idx in range(main_heading_idx + 1, toc_heading_idx):
            block = page_blocks_sorted[idx]
            if block.get("type") == "heading2":
                errors.append(f"[X] TOC heading must be the first section after title, found another heading_2 at idx {idx}")
            else:
                checks_passed.append(f"[C] TOC heading must be the first section after title, found another heading_2 at idx {idx}")
    
        # 5. Find yellow callout with '🔍' icon after TOC heading
        callout_idx = None
        for idx in range(toc_heading_idx + 1, min(toc_heading_idx + 5, len(page_blocks_sorted))):
            block = page_blocks_sorted[idx]
            if block.get("type") == "callout":
                props = block.get("properties", {})
                content = block.get("content", "").lower()
                bg_color = props.get("backgroundColor", "").lower()
                icon = props.get("icon", "")
            
                if ("yellow" in bg_color or bg_color == "yellow_background") and "🔍" in icon:
                    if "quick navigation" in content and "wiki sections" in content:
                        callout_idx = idx
                        break
    
        if callout_idx is None:
            errors.append("[X] Yellow callout with '🔍' icon and 'Quick navigation to all wiki sections' not found after TOC heading")
        else:
            checks_passed.append("[C] Yellow callout with '🔍' icon and 'Quick navigation to all wiki sections' found after TOC heading")
    
        # 6. Find numbered list items after callout
        numbered_list_items = []
        list_start_idx = None
        for idx in range(callout_idx + 1, len(page_blocks_sorted)):
            block = page_blocks_sorted[idx]
            if block.get("type") == "numberedList":
                if list_start_idx is None:
                    list_start_idx = idx
                numbered_list_items.append(block)
            elif list_start_idx is not None and block.get("type") != "numberedList":
                # Stop collecting when we hit a non-numbered list after starting
                break
    
        if len(numbered_list_items) == 0:
            errors.append("[X] No numbered list items found for table of contents")
        else:
            checks_passed.append("[C] numbered list items found for table of contents")
    
        # 7. Find all original heading_2 blocks (excluding the TOC heading itself)
        original_heading_2_blocks = []
        for block in page_blocks_sorted:
            if block.get("type") == "heading2":
                content = block.get("content", "").lower()
                # Skip TOC heading
                if "table of contents" not in content:
                    original_heading_2_blocks.append(block)
    
        # Verify we have the expected number of list items (one per original heading_2)
        if len(numbered_list_items) != len(original_heading_2_blocks):
            errors.append(f"[X] Expected {len(original_heading_2_blocks)} numbered list items (one per heading_2), found {len(numbered_list_items)}")
        else:
            checks_passed.append(f"[C] Expected {len(original_heading_2_blocks)} numbered list items (one per heading_2), found {len(numbered_list_items)}")
    
        # 8. Validate each numbered list item contains correct section info
        # Calculate expected counts for each section
        section_stats = []
        for i, h2_block in enumerate(original_heading_2_blocks):
            h2_order = h2_block.get("order", 0)
            h2_content = h2_block.get("content", "")
        
            # Find next heading_2 order (or end of page)
            next_h2_order = float('inf')
            for j in range(i + 1, len(original_heading_2_blocks)):
                next_h2_order = original_heading_2_blocks[j].get("order", 0)
                break
        
            # Count paragraphs and lists in this section
            paragraph_count = 0
            list_count = 0
            in_list = False
            prev_list_type = None
        
            for block in page_blocks_sorted:
                block_order = block.get("order", 0)
                block_type = block.get("type", "")
            
                # Skip blocks before this section or after
                if block_order <= h2_order or block_order >= next_h2_order:
                    continue
            
                if block_type == "paragraph":
                    paragraph_count += 1
                    in_list = False
                    prev_list_type = None
                elif block_type in ["bulletedList", "numberedList"]:
                    # Count consecutive list items as one list
                    if not in_list or prev_list_type != block_type:
                        list_count += 1
                        in_list = True
                        prev_list_type = block_type
                elif block_type in ["heading1", "heading2", "heading3"]:
                    # Headings don't reset list counting but aren't paragraphs
                    in_list = False
                    prev_list_type = None
                else:
                    in_list = False
                    prev_list_type = None
        
            section_stats.append({
                "heading": h2_content,
                "paragraphs": paragraph_count,
                "lists": list_count
            })
    
        # Validate list item content against expected sections
        for i, (list_item, stats) in enumerate(zip(numbered_list_items, section_stats)):
            list_content = list_item.get("content", "").lower()
            expected_heading = stats["heading"].lower()
            expected_paragraphs = stats["paragraphs"]
            expected_lists = stats["lists"]
        
            # Check heading text is present
            # Remove emoji from heading for comparison
            heading_text_clean = re.sub(r'[^\w\s]', '', expected_heading).strip()
            if heading_text_clean and heading_text_clean not in re.sub(r'[^\w\s]', '', list_content):
                errors.append(f"[X] Numbered list item {i+1} should contain heading '{stats['heading']}', got '{list_item.get('content')}'")
            else:
                checks_passed.append(f"[C] Numbered list item {i+1} should contain heading '{stats['heading']}', got '{list_item.get('content')}'")
        
            # Check paragraph count
            if f"{expected_paragraphs} paragraph" not in list_content:
                errors.append(f"[X] Numbered list item {i+1} should show '{expected_paragraphs} paragraphs', got '{list_item.get('content')}'")
            else:
                checks_passed.append(f"[C] Numbered list item {i+1} should show '{expected_paragraphs} paragraphs', got '{list_item.get('content')}'")
        
            # Check list count
            if f"{expected_lists} list" not in list_content:
                errors.append(f"[X] Numbered list item {i+1} should show '{expected_lists} lists', got '{list_item.get('content')}'")
            else:
                checks_passed.append(f"[C] Numbered list item {i+1} should show '{expected_lists} lists', got '{list_item.get('content')}'")
    
        # 9. Find divider after the numbered list
        divider_idx = None
        list_end_idx = list_start_idx + len(numbered_list_items)
        for idx in range(list_end_idx, min(list_end_idx + 3, len(page_blocks_sorted))):
            block = page_blocks_sorted[idx]
            if block.get("type") == "divider":
                divider_idx = idx
                break
    
        if divider_idx is None:
            errors.append("[X] Divider not found after table of contents numbered list")
        else:
            checks_passed.append("[C] Divider found after table of contents numbered list")
    
        # 10. Find italic paragraph with totals after divider
        summary_para_idx = None
        for idx in range(divider_idx + 1, min(divider_idx + 3, len(page_blocks_sorted))):
            block = page_blocks_sorted[idx]
            if block.get("type") == "paragraph":
                content = block.get("content", "").lower()
                if "total sections" in content and "total content blocks" in content:
                    summary_para_idx = idx
                    break
    
        if summary_para_idx is None:
            errors.append("[X] Summary paragraph with 'Total sections' and 'Total content blocks' not found after divider")
        else:
            checks_passed.append("[C] Summary paragraph with 'Total sections' and 'Total content blocks' found after divider")
    
        summary_para = page_blocks_sorted[summary_para_idx]
        summary_content = summary_para.get("content", "")
    
        # Check for italic formatting (either via properties or markdown-style asterisks)
        has_italic = False
        props = summary_para.get("properties", {})
        if props.get("italic") or props.get("isItalic"):
            has_italic = True
        # Also accept markdown-style italics with asterisks
        if summary_content.startswith("*") and summary_content.endswith("*"):
            has_italic = True
    
        if not has_italic:
            errors.append(f"[X] Summary paragraph should be in italic format, got '{summary_content}'")
        else:
            checks_passed.append(f"[C] Summary paragraph should be in italic format, got '{summary_content}'")
    
        # Calculate expected totals
        total_sections = len(original_heading_2_blocks)
        total_content_blocks = 0
        for stats in section_stats:
            # Count all blocks in sections (paragraphs + list items, could also include heading3s)
            total_content_blocks += stats["paragraphs"]
            total_content_blocks += stats["lists"]
    
        # Also count heading3s and other blocks under sections
        for h2_block in original_heading_2_blocks:
            h2_order = h2_block.get("order", 0)
            h2_idx = original_heading_2_blocks.index(h2_block)
            next_h2_order = float('inf')
            if h2_idx + 1 < len(original_heading_2_blocks):
                next_h2_order = original_heading_2_blocks[h2_idx + 1].get("order", 0)
        
            for block in page_blocks_sorted:
                block_order = block.get("order", 0)
                block_type = block.get("type", "")
                if block_order <= h2_order or block_order >= next_h2_order:
                    continue
                if block_type == "heading3":
                    total_content_blocks += 1
                elif block_type in ["bulletedList", "numberedList"]:
                    total_content_blocks += 1  # Count each list item as a block
    
        # Recalculate: simpler approach - just count all blocks under sections
        total_content_blocks = 0
        for h2_block in original_heading_2_blocks:
            h2_order = h2_block.get("order", 0)
            h2_idx = original_heading_2_blocks.index(h2_block)
            next_h2_order = float('inf')
            if h2_idx + 1 < len(original_heading_2_blocks):
                next_h2_order = original_heading_2_blocks[h2_idx + 1].get("order", 0)
        
            for block in page_blocks_sorted:
                block_order = block.get("order", 0)
                block_type = block.get("type", "")
                if block_order <= h2_order or block_order >= next_h2_order:
                    continue
                # Count all content blocks (not headings)
                if block_type not in ["heading1", "heading2"]:
                    total_content_blocks += 1
    
        # Verify totals in summary
        summary_lower = summary_content.lower()
        if str(total_sections) not in summary_content:
            errors.append(f"[X] Summary should contain total sections: {total_sections}, got '{summary_content}'")
        else:
            checks_passed.append(f"[C] Summary should contain total sections: {total_sections}, got '{summary_content}'")
    
        # More lenient check for total blocks - the count might vary based on interpretation
        # Just verify the format is correct and contains numbers
        if not re.search(r'total content blocks[:\s]+\d+', summary_lower):
            errors.append(f"[X] Summary should contain 'Total content blocks: [number]', got '{summary_content}'")
        else:
            checks_passed.append(f"[C] Summary should contain 'Total content blocks: [number]', got '{summary_content}'")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

    # -----------------------------------------------------------------------------
    # Task: marketing-campaign-planner
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_marketing_campaign_planner(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate marketing campaign planner template on Marketing Ideas page.
    
    Success criteria:
    1. Marketing Ideas page (page-12) contains heading1 '💡 Marketing Campaign Planner'
    2. heading2 '🎯 Q1 2024 Campaigns' exists
    3. Purple callout with 🚀 icon contains 'Theme: Innovation & Growth - Showcasing our latest features'
    4. Three heading3 blocks: '📱 Social Media Blitz', '📧 Email Nurture Series', '🎪 Virtual Event Series'
    5. Each heading3 is followed by exactly 3 numbered list items with specified content
    6. Ends with a divider followed by quote block containing Tom Fishburne quote
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    
    # 1. Find the Marketing Ideas page (page-12)
    try:
        marketing_page = _find_page_by_title(final_state_backend, "Marketing Ideas")
        if not marketing_page:
            errors.append("[X] Marketing Ideas page not found")
        else:
            checks_passed.append("[C] Marketing Ideas page found")
    
        page_id = marketing_page.get("_id")
        page_blocks = _get_blocks_for_page(final_state_backend, page_id)
    
        if not page_blocks:
            errors.append("[X] No blocks found on Marketing Ideas page")
        else:
            checks_passed.append("[C] blocks found on Marketing Ideas page")
    
        # Sort blocks by order
        page_blocks_sorted = sorted(page_blocks, key=lambda x: x.get("order", 0))
    
        # 2. Verify heading1 '💡 Marketing Campaign Planner' exists
        main_heading = None
        for block in page_blocks_sorted:
            if block.get("type") == "heading1":
                content = block.get("content", "")
                if "Marketing Campaign Planner" in content and "💡" in content:
                    main_heading = block
                    break
    
        if not main_heading:
            errors.append("[X] Missing heading1 '💡 Marketing Campaign Planner'")
        else:
            checks_passed.append("[C] has heading1 '💡 Marketing Campaign Planner'")
    
        # 3. Verify heading2 '🎯 Q1 2024 Campaigns' exists
        q1_heading = None
        for block in page_blocks_sorted:
            if block.get("type") == "heading2":
                content = block.get("content", "")
                if "Q1 2024 Campaigns" in content and "🎯" in content:
                    q1_heading = block
                    break
    
        if not q1_heading:
            errors.append("[X] Missing heading2 '🎯 Q1 2024 Campaigns'")
        else:
            checks_passed.append("[C] has heading2 '🎯 Q1 2024 Campaigns'")
    
        # 4. Verify purple callout with 🚀 icon containing theme text
        theme_callout = None
        for block in page_blocks_sorted:
            if block.get("type") == "callout":
                props = block.get("properties", {})
                bg_color = props.get("backgroundColor", "")
                icon = props.get("icon", "")
                content = block.get("content", "")
            
                if ("purple" in bg_color.lower() and 
                    "🚀" in icon and 
                    "Theme: Innovation & Growth" in content and
                    "Showcasing our latest features" in content):
                    theme_callout = block
                    break
    
        if not theme_callout:
            errors.append("[X] Missing purple callout with 🚀 icon containing  Theme: Innovation & Growth - Showcasing our latest features")
        else:
            checks_passed.append("[C] has purple callout with 🚀 icon containing Theme: Innovation & Growth - Showcasing our latest features")
    
        # 5. Verify three heading3 blocks exist
        expected_heading3s = [
            ("📱 Social Media Blitz", [
                "Launch teaser videos on TikTok/Instagram",
                "LinkedIn thought leadership articles",
                "Twitter spaces with industry experts"
            ]),
            ("📧 Email Nurture Series", [
                "Welcome series for new signups",
                "Feature spotlight newsletters",
                "Customer success stories"
            ]),
            ("🎪 Virtual Event Series", [
                "Monthly product demos",
                "Customer panel discussions",
                "Technical deep-dives for developers"
            ])
        ]
    
        found_heading3s = []
        for block in page_blocks_sorted:
            if block.get("type") == "heading3":
                content = block.get("content", "")
                for expected_title, _ in expected_heading3s:
                    # Check if the key part of the title is present
                    title_text = expected_title.split(" ", 1)[1] if " " in expected_title else expected_title
                    emoji = expected_title.split(" ")[0] if " " in expected_title else ""
                    if title_text in content and (not emoji or emoji in content):
                        found_heading3s.append((block, expected_title))
                        break
    
        if len(found_heading3s) != 3:
            found_titles = [h[1] for h in found_heading3s]
            expected_titles = [h[0] for h in expected_heading3s]
            missing = [t for t in expected_titles if t not in found_titles]
            errors.append(f"[X] Expected 3 heading3 blocks, found {len(found_heading3s)}. Missing: {missing}")
        else:
            checks_passed.append(f"[C] Found 3 heading3 blocks as expected")
    
        # 6. Validate numbered lists under each heading3
        for heading_block, expected_title in found_heading3s:
            heading_order = heading_block.get("order", 0)
        
            # Find the expected numbered items for this heading
            expected_items = None
            for title, items in expected_heading3s:
                if title == expected_title:
                    expected_items = items
                    break
        
            if not expected_items:
                continue
        
            # Find numbered list items after this heading
            numbered_items = []
            for block in page_blocks_sorted:
                block_order = block.get("order", 0)
                # Only look at blocks after this heading
                if block_order <= heading_order:
                    continue
            
                # Stop if we hit another heading
                if block.get("type") in ["heading1", "heading2", "heading3"]:
                    break
            
                # Collect numbered list items
                if block.get("type") == "numberedList":
                    numbered_items.append(block)
        
            if len(numbered_items) != 3:
                errors.append(f"[X] Expected exactly 3 numbered list items under {expected_title},  found {len(numbered_items)}")
            else:
                checks_passed.append(f"[C] Expected exactly 3 numbered list items under {expected_title}, found {len(numbered_items)}")
        
            # Verify the content of each numbered item
            for i, item in enumerate(numbered_items):
                item_content = item.get("content", "")
                expected_text = expected_items[i]
                if expected_text.lower() not in item_content.lower():
                    errors.append(f"[X] Numbered list item {i+1} under {expected_title} has wrong content.  Expected to contain: {expected_text}, Got: {item_content}")
                else:
                    checks_passed.append(f"[C] Numbered list item {i+1} under {expected_title} has wrong content. Expected to contain: {expected_text}, Got: {item_content}")
    
        # 7. Verify divider exists before the quote
        divider_found = False
        quote_block = None
    
        for block in page_blocks_sorted:
            if block.get("type") == "divider":
                divider_found = True
            elif block.get("type") == "quote":
                quote_block = block
    
        if not divider_found:
            errors.append("[X] Missing divider before the quote block")
        else:
            checks_passed.append("[C] has divider before the quote block")
    
        if not quote_block:
            errors.append("[X] Missing quote block at the end")
        else:
            checks_passed.append("[C] has quote block at the end")
    
        # 8. Verify quote contains Tom Fishburne quote
        quote_content = quote_block.get("content", "")
        expected_quote = "The best marketing doesn't feel like marketing"
        expected_author = "Tom Fishburne"
    
        if expected_quote.lower() not in quote_content.lower():
            errors.append(f"[X] Quote block has wrong content.  Expected to contain: {expected_quote}, Got: {quote_content}")
        else:
            checks_passed.append(f"[C] Quote block has wrong content. Expected to contain: {expected_quote}, Got: {quote_content}")
    
        if expected_author.lower() not in quote_content.lower():
            errors.append(f"[X] Quote block missing author.  Expected to contain: {expected_author}, Got: {quote_content}")
        else:
            checks_passed.append(f"[C] Quote block has author. Expected to contain: {expected_author}, Got: {quote_content}")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

    # -----------------------------------------------------------------------------
    # Task: bug-tracker-status-summary
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_bug_tracker_status_summary(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate bug tracker status summary task.
    
    Requirements:
    1. Navigate to Bug Tracker page
    2. Count all todo blocks and categorize by checked status
    3. Insert new section AFTER 'Low Priority' heading but BEFORE existing todos
    4. Add heading_3 '📊 Bug Status Summary' with bold formatting
    5. Add callout with orange_background and '📈' icon with metrics
    6. Add divider block
    7. Add quote block with italic Aristotle quote
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    
    # 1. Find Bug Tracker page
    try:
        bug_tracker = _find_page_by_title(final_state_backend, "Bug Tracker")
        if not bug_tracker:
            errors.append("[X] Bug Tracker page not found")
        else:
            checks_passed.append("[C] Bug Tracker page found")
    
        bug_tracker_id = bug_tracker.get("_id")
    
        # 2. Get all blocks for Bug Tracker page and sort by order
        bt_blocks = _get_blocks_for_page(final_state_backend, bug_tracker_id)
        bt_blocks_sorted = sorted(bt_blocks, key=lambda x: x.get("order", 0))
    
        if not bt_blocks_sorted:
            errors.append("[X] No blocks found in Bug Tracker page")
        else:
            checks_passed.append("[C] blocks found in Bug Tracker page")
    
        # 3. Count todos - expected: 5 total (2 checked, 3 unchecked)
        # Based on initial data:
        # - Critical: 1 checked (Fix login timeout), 1 unchecked (Resolve data sync)
        # - Medium: 1 checked (Image upload), 1 unchecked (Search results)  
        # - Low: 1 unchecked (Tooltip text)
        todos = [b for b in bt_blocks_sorted if b.get("type") == "todo"]
        checked_todos = [t for t in todos if t.get("properties", {}).get("checked")]
        unchecked_todos = [t for t in todos if not t.get("properties", {}).get("checked")]
    
        total_bugs = len(todos)
        fixed_bugs = len(checked_todos)
        active_bugs = len(unchecked_todos)
    
        # Calculate expected percentages
        fixed_percentage = round((fixed_bugs / total_bugs * 100) if total_bugs > 0 else 0)
        active_percentage = round((active_bugs / total_bugs * 100) if total_bugs > 0 else 0)
    
        # 4. Find 'Low Priority' heading and verify new section placement
        low_priority_idx = None
        for idx, block in enumerate(bt_blocks_sorted):
            if block.get("type") == "heading2" and "low priority" in block.get("content", "").lower():
                low_priority_idx = idx
                break
    
        if low_priority_idx is None:
            errors.append("[X] Low Priority heading not found in Bug Tracker page")
        else:
            checks_passed.append("[C] Low Priority heading found in Bug Tracker page")
    
        # 5. Look for the new section blocks after Low Priority heading
        # The new section should be: heading3, callout, divider, quote
        remaining_blocks = bt_blocks_sorted[low_priority_idx + 1:]
    
        if len(remaining_blocks) < 4:
            errors.append(f"[X] Not enough blocks after 'Low Priority' heading. Expected at least 4 new blocks, found {len(remaining_blocks)}")
        else:
            checks_passed.append(f"[C] enough blocks after 'Low Priority' heading. Found at least 4 new blocks ({len(remaining_blocks)})")
    
        # 6. Verify heading_3 '📊 Bug Status Summary'
        heading3_block = remaining_blocks[0]
        if heading3_block.get("type") != "heading3":
            errors.append(f"[X] First block after 'Low Priority' should be heading3, got {heading3_block.get('type')}")
        else:
            checks_passed.append(f"[C] First block after 'Low Priority' should be heading3, got {heading3_block.get('type')}")
    
        heading3_content = heading3_block.get("content", "")
        if "bug status summary" not in heading3_content.lower():
            errors.append(f"[X] heading3 should contain 'Bug Status Summary', got '{heading3_content}'")
        else:
            checks_passed.append(f"[C] heading3 should contain 'Bug Status Summary', got '{heading3_content}'")
    
        # Check for bold formatting (properties.bold or **text** pattern)
        heading3_props = heading3_block.get("properties", {})
        has_bold = heading3_props.get("bold", False) or "**" in heading3_content
        if not has_bold:
            # Some implementations might store bold differently, be lenient
            pass  # We'll accept the heading even without explicit bold verification
    
        # 7. Verify callout block with orange_background and '📈' icon
        callout_block = remaining_blocks[1]
        if callout_block.get("type") != "callout":
            errors.append(f"[X] Second block after 'Low Priority' should be callout, got {callout_block.get('type')}")
        else:
            checks_passed.append(f"[C] Second block after 'Low Priority' should be callout, got {callout_block.get('type')}")
    
        callout_props = callout_block.get("properties", {})
        bg_color = callout_props.get("backgroundColor", "")
        if bg_color != "orange" and bg_color != "orange_background":
            errors.append(f"[X] Callout should have orange background, got '{bg_color}'")
        else:
            checks_passed.append(f"[C] Callout should have orange background, got '{bg_color}'")
    
        callout_icon = callout_props.get("icon", "")
        if callout_icon != "📈":
            errors.append(f"[X] Callout should have '📈' icon, got '{callout_icon}'")
        else:
            checks_passed.append(f"[C] Callout should have '📈' icon, got '{callout_icon}'")
    
        # 8. Verify callout content with accurate metrics
        callout_content = callout_block.get("content", "").lower()
    
        if "critical metrics" not in callout_content:
            errors.append(f"[X] Callout should contain 'Critical Metrics', got '{callout_block.get('content')}'")
        else:
            checks_passed.append(f"[C] Callout should contain 'Critical Metrics', got '{callout_block.get('content')}'")
    
        # Check total bugs count
        if f"total bugs: {total_bugs}" not in callout_content:
            errors.append(f"[X] Callout should contain 'Total bugs: {total_bugs}', got '{callout_block.get('content')}'")
        else:
            checks_passed.append(f"[C] Callout should contain 'Total bugs: {total_bugs}', got '{callout_block.get('content')}'")
    
        # Check fixed bugs count and percentage
        if f"fixed: {fixed_bugs}" not in callout_content:
            errors.append(f"[X] Callout should contain 'Fixed: {fixed_bugs}', got '{callout_block.get('content')}'")
        else:
            checks_passed.append(f"[C] Callout should contain 'Fixed: {fixed_bugs}', got '{callout_block.get('content')}'")
    
        if f"{fixed_percentage}%" not in callout_content:
            errors.append(f"[X] Callout should contain '{fixed_percentage}%' for fixed bugs, got '{callout_block.get('content')}'")
        else:
            checks_passed.append(f"[C] Callout should contain '{fixed_percentage}%' for fixed bugs, got '{callout_block.get('content')}'")
    
        # Check active bugs count and percentage
        if f"active: {active_bugs}" not in callout_content:
            errors.append(f"[X] Callout should contain 'Active: {active_bugs}', got '{callout_block.get('content')}'")
        else:
            checks_passed.append(f"[C] Callout should contain 'Active: {active_bugs}', got '{callout_block.get('content')}'")
    
        if f"{active_percentage}%" not in callout_content:
            errors.append(f"[X] Callout should contain '{active_percentage}%' for active bugs, got '{callout_block.get('content')}'")
        else:
            checks_passed.append(f"[C] Callout should contain '{active_percentage}%' for active bugs, got '{callout_block.get('content')}'")
    
        # 9. Verify divider block
        divider_block = remaining_blocks[2]
        if divider_block.get("type") != "divider":
            errors.append(f"[X] Third block after callout should be divider, got {divider_block.get('type')}")
        else:
            checks_passed.append(f"[C] Third block after callout should be divider, got {divider_block.get('type')}")
    
        # 10. Verify quote block with italic Aristotle quote
        quote_block = remaining_blocks[3]
        if quote_block.get("type") != "quote":
            errors.append(f"[X] Fourth block should be quote, got {quote_block.get('type')}")
        else:
            checks_passed.append(f"[C] Fourth block should be quote, got {quote_block.get('type')}")
    
        quote_content = quote_block.get("content", "")
        expected_quote = "quality is not an act, it is a habit"
    
        if expected_quote not in quote_content.lower():
            errors.append(f"[X] Quote should contain '{expected_quote}', got '{quote_content}'")
        else:
            checks_passed.append(f"[C] Quote should contain '{expected_quote}', got '{quote_content}'")
    
        if "aristotle" not in quote_content.lower():
            errors.append(f"[X] Quote should attribute to Aristotle, got '{quote_content}'")
        else:
            checks_passed.append(f"[C] Quote should attribute to Aristotle, got '{quote_content}'")
    
        # Check for italic formatting (properties.italic or *text* pattern)
        quote_props = quote_block.get("properties", {})
        has_italic = quote_props.get("italic", False) or "*" in quote_content
        if not has_italic:
            # Some implementations might store italic differently, be lenient
            pass  # We'll accept the quote even without explicit italic verification
    
        # 11. Verify that the original Low Priority todo comes AFTER the new section
        # Find the original todo in remaining blocks
        original_todo_found = False
        for idx, block in enumerate(remaining_blocks[4:], start=4):
            if block.get("type") == "todo" and "tooltip" in block.get("content", "").lower():
                original_todo_found = True
                break
    
        if not original_todo_found:
            errors.append("[X] Original Low Priority todo 'Tooltip text cut off on small screens' not found after new section")
        else:
            checks_passed.append("[C] Original Low Priority todo 'Tooltip text cut off on small screens' found after new section")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

    # -----------------------------------------------------------------------------
    # Task: performance-guidelines-insertion
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_performance_guidelines_insertion(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate precise content insertion on Project Guidelines & Best Practices page.
    
    Goal: Insert performance guidelines content AFTER the 5th callout but BEFORE the 6th callout.
    
    Validation steps:
    1. Find the 'Project Guidelines & Best Practices' page (page-21)
    2. Get all blocks for this page sorted by order
    3. Identify all callout blocks and their positions
    4. Verify new content appears between 5th and 6th original callouts:
       - heading_2 with '🚀 Performance Guidelines'
       - numbered list with exactly 3 items with specified text
       - callout with purple_background, ⚡ icon, and performance target text
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    
    # 1. Find the Project Guidelines & Best Practices page
    try:
        guidelines_page = _find_page_by_title(final_state_backend, "Project Guidelines & Best Practices")
        if not guidelines_page:
            errors.append("[X] Project Guidelines & Best Practices page not found")
        else:
            checks_passed.append("[C] Project Guidelines & Best Practices page found")
    
        page_id = guidelines_page.get("_id")
    
        # 2. Get all blocks for this page sorted by order
        all_blocks = final_state_backend.query({
            "collection": "blocks",
            "filter": {"pageId": page_id}
        })
        page_blocks = [b for b in all_blocks if b.get("pageId") == page_id]
        page_blocks_sorted = sorted(page_blocks, key=lambda b: b.get("order", 0))
    
        if not page_blocks_sorted:
            errors.append("[X] No blocks found on the page")
        else:
            checks_passed.append("[C] blocks found on the page")
    
        # 3. Get all callouts on the page (both original and new) - validate by content pattern
        # The original 5th callout content: "Note: Update the changelog for all user-facing changes."
        # The original 6th callout content: "Security: All user inputs must be sanitized and validated."
        all_callouts = [b for b in page_blocks_sorted if b.get("type") == "callout"]
    
        # Find the 5th and 6th original callouts by their CONTENT (not IDs, since MCP may recreate blocks)
        fifth_callout_content = "Note: Update the changelog for all user-facing changes."
        sixth_callout_content = "Security: All user inputs must be sanitized and validated."
    
        # Find first occurrence of 5th callout content
        fifth_callout = next(
            (b for b in all_callouts if fifth_callout_content in b.get("content", "")), 
            None
        )
        # Find the 6th callout - it should appear AFTER any new inserted content
        # Look for the first "Security" callout that appears after the inserted content
        sixth_callout = None
        for b in all_callouts:
            content = b.get("content", "")
            if sixth_callout_content in content:
                # This is a candidate for the 6th callout
                # We need the one that appears AFTER the performance guidelines section
                sixth_callout = b
                break  # Take the first match after searching through ordered blocks
    
        # Actually, let's find them more carefully - find 5th callout, then find 6th after it
        fifth_callout = None
        for b in page_blocks_sorted:
            if b.get("type") == "callout" and fifth_callout_content in b.get("content", ""):
                fifth_callout = b
                break
    
        if not fifth_callout:
            errors.append(f"[X] 5th original callout with content '{fifth_callout_content}' not found")
        else:
            checks_passed.append(f"[C] 5th original callout with content '{fifth_callout_content}' found")
    
        fifth_order = fifth_callout.get("order", 0)
    
        # Find 6th callout - should be the first "Security" callout AFTER the inserted content
        # The inserted content should appear right after 5th callout
        sixth_callout = None
        for b in page_blocks_sorted:
            if (b.get("type") == "callout" and 
                sixth_callout_content in b.get("content", "") and
                b.get("order", 0) > fifth_order):
                sixth_callout = b
                break
    
        if not sixth_callout:
            errors.append(f"[X] 6th original callout with content '{sixth_callout_content}' not found after 5th callout")
        else:
            checks_passed.append(f"[C] 6th original callout with content '{sixth_callout_content}' found after 5th callout")
    
        sixth_order = sixth_callout.get("order", 0)
    
        # 4. Find blocks inserted between 5th and 6th callout
        inserted_blocks = [
            b for b in page_blocks_sorted 
            if b.get("order", 0) > fifth_order and b.get("order", 0) < sixth_order
        ]
    
        if not inserted_blocks:
            errors.append(f"[X] No blocks found between 5th callout (order {fifth_order}) and 6th callout (order {sixth_order})")
        else:
            checks_passed.append(f"[C] blocks found between 5th callout (order {fifth_order}) and 6th callout (order {sixth_order})")
    
        # 5. Validate heading_2 with '🚀 Performance Guidelines'
        heading_block = next(
            (b for b in inserted_blocks if b.get("type") in ["heading2", "heading_2"]), 
            None
        )
        if not heading_block:
            errors.append("[X] heading_2 block not found in inserted content")
        else:
            checks_passed.append("[C] heading_2 block found in inserted content")
    
        heading_content = heading_block.get("content", "")
        if "Performance Guidelines" not in heading_content:
            errors.append(f"[X] heading_2 missing 'Performance Guidelines' text. Found: '{heading_content}'")
        else:
            checks_passed.append(f"[C] heading_2 has 'Performance Guidelines' text. Found: '{heading_content}'")
    
        # 6. Validate numbered list with exactly 3 items
        numbered_list_blocks = [
            b for b in inserted_blocks 
            if b.get("type") in ["numberedList", "numbered_list", "numberedListItem", "numbered_list_item"]
        ]
    
        if len(numbered_list_blocks) != 3:
            errors.append(f"[X] Expected exactly 3 numbered list items, found {len(numbered_list_blocks)}")
        else:
            checks_passed.append(f"[C] Expected exactly 3 numbered list items, found {len(numbered_list_blocks)}")
    
        # Verify each list item's content
        required_list_items = [
            "Optimize images before uploading (max 200KB)",
            "Lazy load components below the fold",
            "Use memoization for expensive computations"
        ]
    
        found_items = []
        for block in numbered_list_blocks:
            content = block.get("content", "")
            for required_item in required_list_items:
                if required_item in content:
                    found_items.append(required_item)
                    break
    
        missing_items = [item for item in required_list_items if item not in found_items]
        if missing_items:
            errors.append(f"[X] Missing numbered list items: {missing_items}")
        else:
            checks_passed.append(f"[C] has numbered list items: {missing_items}")
    
        # 7. Validate new callout with purple_background, ⚡ icon, and performance target text
        # Find the performance callout by its content (not by ID exclusion)
        performance_callout = None
        for block in inserted_blocks:
            if block.get("type") == "callout":
                content = block.get("content", "")
                if "Performance target" in content or "First contentful paint" in content:
                    performance_callout = block
                    break
    
        if not performance_callout:
            errors.append("[X] Performance target callout not found in inserted content")
        else:
            checks_passed.append("[C] Performance target callout found in inserted content")
    
        # Check callout properties
        properties = performance_callout.get("properties", {})
        background_color = properties.get("backgroundColor", "")
        icon = properties.get("icon", "")
        content = performance_callout.get("content", "")
    
        if background_color != "purple_background":
            errors.append(f"[X] Performance callout has wrong background. Expected 'purple_background', found '{background_color}'")
        else:
            checks_passed.append(f"[C] Performance callout has wrong background. Expected 'purple_background', found '{background_color}'")
    
        if "⚡" not in icon:
            errors.append(f"[X] Performance callout has wrong icon. Expected '⚡', found '{icon}'")
        else:
            checks_passed.append(f"[C] Performance callout has wrong icon. Expected '⚡', found '{icon}'")
    
        if "Performance target: First contentful paint < 1.5s" not in content:
            errors.append(f"[X] Performance callout has wrong text. Expected 'Performance target: First contentful paint < 1.5s', found '{content}'")
        else:
            checks_passed.append(f"[C] Performance callout has wrong text. Expected 'Performance target: First contentful paint < 1.5s', found '{content}'")
    
        # 8. Verify order: heading -> numbered list -> callout
        heading_order = heading_block.get("order", 0)
        list_orders = [b.get("order", 0) for b in numbered_list_blocks]
        callout_order = performance_callout.get("order", 0)
    
        if not (heading_order < min(list_orders)):
            errors.append("[X] Heading should appear before numbered list items")
        else:
            checks_passed.append("[C] Heading should appear before numbered list items")
    
        if not (max(list_orders) < callout_order):
            errors.append("[X] Numbered list should appear before performance callout")
        else:
            checks_passed.append("[C] Numbered list should appear before performance callout")
    
        # All validations passed
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

    # -----------------------------------------------------------------------------
    # Task: weekly-standup-in-progress-items
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_weekly_standup_in_progress_items(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate weekly standup in-progress items section task.
    
    Goal: Add an 'In Progress Items' section between 'What I did this week' and 
    'What I plan to do next week', plus a divider and callout after 'Blockers'.
    
    Validation steps (ordered):
    1. Find the 'Weekly Standup Template' page (page-9)
    2. Get all blocks sorted by order
    3. Verify heading_2 '🔄 In Progress Items' exists AFTER 'What I did this week' section
       (after block-9-5) but BEFORE 'What I plan to do next week' heading (block-9-6)
    4. Verify exactly 3 unchecked todo blocks with exact texts appear after the new heading:
       - '🔧 Refactoring authentication module'
       - '📝 Writing unit tests for payment service'
       - '🔍 Code review for PR #234'
    5. Verify a divider block appears after the 'Blockers' section (after block-9-10)
    6. Verify a callout block with yellow_background, icon '⏰', and text 
       'Standup scheduled for Monday 10 AM' appears after the divider
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    
    # 1. Find Weekly Standup Template page (page-9)
    try:
        standup_page = _find_page_by_title(final_state_backend, "Weekly Standup Template")
        if not standup_page:
            errors.append("[X] Weekly Standup Template page not found")
        else:
            checks_passed.append("[C] Weekly Standup Template page found")
    
        page_id = standup_page.get("_id")
        page_blocks = _get_blocks_for_page(final_state_backend, page_id)
    
        if not page_blocks:
            errors.append("[X] No blocks found on Weekly Standup Template page")
        else:
            checks_passed.append("[C] blocks found on Weekly Standup Template page")
    
        # Sort blocks by order to ensure correct sequence
        page_blocks_sorted = sorted(page_blocks, key=lambda b: b.get("order", 0))
    
        # 2. Find key reference points in the page
        what_i_did_heading_idx = None
        what_i_did_last_todo_idx = None
        what_i_plan_heading_idx = None
        blockers_heading_idx = None
        blockers_last_item_idx = None
        in_progress_heading_idx = None
    
        for idx, block in enumerate(page_blocks_sorted):
            block_id = block.get("_id", "")
            content = block.get("content", "")
            content_lower = content.lower()
            block_type = block.get("type", "")
        
            # Find 'What I did this week' heading (block-9-3)
            if block_type == "heading2" and "what i did this week" in content_lower:
                what_i_did_heading_idx = idx
        
            # Find block-9-5 (last todo under 'What I did this week': 'Reviewed pull requests from team members')
            if block_id == "block-9-5" or "reviewed pull requests from team members" in content_lower:
                what_i_did_last_todo_idx = idx
        
            # Find 'What I plan to do next week' heading (block-9-6)
            if block_type == "heading2" and "what i plan to do next week" in content_lower:
                what_i_plan_heading_idx = idx
        
            # Find 'Blockers' heading (block-9-9)
            if block_type == "heading2" and "blockers" in content_lower:
                blockers_heading_idx = idx
        
            # Find block-9-10 (last item under Blockers: 'Waiting for design review on component Z')
            if block_id == "block-9-10" or "waiting for design review on component z" in content_lower:
                blockers_last_item_idx = idx
        
            # Find the new '🔄 In Progress Items' heading
            if block_type == "heading2" and "in progress items" in content_lower:
                in_progress_heading_idx = idx
    
        # Validation: ensure we found the reference points
        if what_i_did_last_todo_idx is None:
            errors.append("[X] 'What I did this week' section last todo (block-9-5) not found")
        else:
            checks_passed.append("[C] 'What I did this week' section last todo (block-9-5) found")
    
        if what_i_plan_heading_idx is None:
            errors.append("[X] 'What I plan to do next week' heading not found")
        else:
            checks_passed.append("[C] 'What I plan to do next week' heading found")
    
        if blockers_last_item_idx is None:
            errors.append("[X] 'Blockers' section last item (block-9-10) not found")
        else:
            checks_passed.append("[C] 'Blockers' section last item (block-9-10) found")
    
        # 3. Verify heading_2 '🔄 In Progress Items' exists in the correct position
        if in_progress_heading_idx is None:
            errors.append("[X] heading_2 '🔄 In Progress Items' not found")
        else:
            checks_passed.append("[C] heading_2 '🔄 In Progress Items' found")
    
        in_progress_block = page_blocks_sorted[in_progress_heading_idx]
        in_progress_content = in_progress_block.get("content", "")
    
        if in_progress_heading_idx <= what_i_did_last_todo_idx:
            errors.append(f"[X] '🔄 In Progress Items' heading must appear AFTER block-9-5 (found at index {in_progress_heading_idx}, block-9-5 at {what_i_did_last_todo_idx})")
        else:
            checks_passed.append(f"[C] '🔄 In Progress Items' heading must appear AFTER block-9-5 (found at index {in_progress_heading_idx}, block-9-5 at {what_i_did_last_todo_idx})")
    
        if in_progress_heading_idx >= what_i_plan_heading_idx:
            errors.append(f"[X] '🔄 In Progress Items' heading must appear BEFORE 'What I plan to do next week' heading (found at index {in_progress_heading_idx}, 'What I plan' at {what_i_plan_heading_idx})")
        else:
            checks_passed.append(f"[C] '🔄 In Progress Items' heading must appear BEFORE 'What I plan to do next week' heading (found at index {in_progress_heading_idx}, 'What I plan' at {what_i_plan_heading_idx})")
    
        # 4. Verify the three required todo blocks exist after the heading
        required_todos = [
            "🔧 Refactoring authentication module",
            "📝 Writing unit tests for payment service",
            "🔍 Code review for PR #234"
        ]
    
        # Look for todos between in_progress_heading_idx and what_i_plan_heading_idx
        found_todos = []
        for idx in range(in_progress_heading_idx + 1, what_i_plan_heading_idx):
            block = page_blocks_sorted[idx]
            if block.get("type") == "todo":
                found_todos.append(block)
    
        if len(found_todos) < 3:
            errors.append(f"[X] Expected 3 todo blocks under '🔄 In Progress Items', found {len(found_todos)}")
        else:
            checks_passed.append(f"[C] Found 3 todo blocks under '🔄 In Progress Items' as expected")
    
        # Check that required todos are present with exact text
        found_todo_texts = [b.get("content", "") for b in found_todos]
    
        for required_todo in required_todos:
            found = False
            for found_text in found_todo_texts:
                # Check for exact or close match
                if required_todo.lower() in found_text.lower() or found_text.lower() in required_todo.lower():
                    found = True
                    break
            if not found:
                errors.append(f"[X] Required todo not found: '{required_todo}'")
            else:
                checks_passed.append(f"[C] Required todo found: '{required_todo}'")
    
        # Verify all new todos are unchecked
        for todo_block in found_todos[:3]:
            properties = todo_block.get("properties", {})
            if properties.get("checked", False):
                errors.append(f"[X] Todo should be unchecked: '{todo_block.get('content', '')}'")
            else:
                checks_passed.append(f"[C] Todo should be unchecked: '{todo_block.get('content', '')}'")
    
        # 5. Verify a divider block appears after the 'Blockers' section
        divider_idx = None
        for idx in range(blockers_last_item_idx + 1, len(page_blocks_sorted)):
            block = page_blocks_sorted[idx]
            if block.get("type") == "divider":
                divider_idx = idx
                break
    
        if divider_idx is None:
            errors.append("[X] Divider block not found after 'Blockers' section")
        else:
            checks_passed.append("[C] Divider block found after 'Blockers' section")
    
        # 6. Verify a callout block with correct properties appears after the divider
        callout_block = None
        for idx in range(divider_idx + 1, len(page_blocks_sorted)):
            block = page_blocks_sorted[idx]
            if block.get("type") == "callout":
                callout_block = block
                break
    
        if callout_block is None:
            errors.append("[X] Callout block not found after divider")
        else:
            checks_passed.append("[C] Callout block found after divider")
    
        # Check callout properties
        callout_content = callout_block.get("content", "")
        callout_props = callout_block.get("properties", {})
        callout_bg = callout_props.get("backgroundColor", "")
        callout_icon = callout_props.get("icon", "")
    
        # Verify yellow_background
        if "yellow" not in callout_bg.lower():
            errors.append(f"[X] Callout should have yellow_background, found '{callout_bg}'")
        else:
            checks_passed.append(f"[C] Callout should have yellow_background, found '{callout_bg}'")
    
        # Verify ⏰ icon
        if "⏰" not in callout_icon:
            errors.append(f"[X] Callout should have '⏰' icon, found '{callout_icon}'")
        else:
            checks_passed.append(f"[C] Callout should have '⏰' icon, found '{callout_icon}'")
    
        # Verify callout text
        expected_callout_text = "Standup scheduled for Monday 10 AM"
        if expected_callout_text.lower() not in callout_content.lower():
            errors.append(f"[X] Callout should contain '{expected_callout_text}', found '{callout_content}'")
        else:
            checks_passed.append(f"[C] Callout should contain '{expected_callout_text}', found '{callout_content}'")
    
        # All validations passed
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

    # -----------------------------------------------------------------------------
    # Task: bug-tracker-performance-issues
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_bug_tracker_performance_issues(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate bug tracker performance issues task.
    
    Goal: Add a '⚡ Performance Issues' section between 'Search results not updating in real-time'
    todo and 'Low Priority' heading, add 3 new unchecked todos, and add a callout at top with bug status metrics.
    
    Validation steps (ordered):
    1. Find the 'Bug Tracker' page (page-11)
    2. Get all blocks sorted by order
    3. Verify heading_2 '⚡ Performance Issues' exists AFTER 'Search results not updating in real-time'
       todo (block-11-8) but BEFORE 'Low Priority' heading (block-11-9)
    4. Verify exactly 3 unchecked todo blocks with exact texts appear after the new heading:
       - '🔧 Memory leak in dashboard view'
       - '📊 Slow query performance on reports page'
       - '🚦 API response time exceeding 2 seconds'
    5. Verify callout with blue_background, icon '📈' appears AFTER 'Bug Tracker' heading (block-11-1)
       but BEFORE the description paragraph (block-11-2)
    6. Verify callout contains 'Bug Status: X total issues, Y resolved (Z% completion rate)'
       with correct calculated values (8 total, 2 resolved, 25%)
    
    Initial state todos (before changes):
    - Critical: 1 checked, 1 unchecked
    - Medium: 1 checked, 1 unchecked
    - Low: 1 unchecked
    Total: 5 todos, 2 checked
    
    After adding 3 new unchecked todos: 8 total, 2 checked, 25% completion
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    
    # 1. Find Bug Tracker page (page-11)
    try:
        bug_tracker = _find_page_by_title(final_state_backend, "Bug Tracker")
        if not bug_tracker:
            errors.append("[X] Bug Tracker page not found")
        else:
            checks_passed.append("[C] Bug Tracker page found")
    
        bug_tracker_id = bug_tracker.get("_id")
        page_blocks = _get_blocks_for_page(final_state_backend, bug_tracker_id)
    
        if not page_blocks:
            errors.append("[X] No blocks found on Bug Tracker page")
        else:
            checks_passed.append("[C] blocks found on Bug Tracker page")
    
        # Sort blocks by order to ensure correct sequence
        page_blocks_sorted = sorted(page_blocks, key=lambda b: b.get("order", 0))
    
        # 2. Count all todos to calculate metrics
        todos = [b for b in page_blocks_sorted if b.get("type") == "todo"]
        checked_todos = [t for t in todos if t.get("properties", {}).get("checked")]
    
        total_todos = len(todos)
        resolved_todos = len(checked_todos)
    
        # Expected: 8 total (5 original + 3 new), 2 checked
        if total_todos < 8:
            errors.append(f"[X] Expected at least 8 todo blocks (5 original + 3 new), found {total_todos}")
        else:
            checks_passed.append(f"[C] Found at least 8 todo blocks (5 original + 3 new) ({total_todos})")
    
        # Calculate expected percentage
        completion_rate = round((resolved_todos / total_todos * 100) if total_todos > 0 else 0)
    
        # 3. Find key reference points in the page
        search_results_todo_idx = None
        low_priority_heading_idx = None
        performance_heading_idx = None
        main_heading_idx = None
        description_paragraph_idx = None
        status_callout_idx = None
    
        for idx, block in enumerate(page_blocks_sorted):
            block_id = block.get("_id", "")
            content = block.get("content", "")
            content_lower = content.lower()
            block_type = block.get("type", "")
        
            # Find main 'Bug Tracker' heading (block-11-1)
            if block_id == "block-11-1" or (block_type == "heading1" and content_lower == "bug tracker"):
                main_heading_idx = idx
        
            # Find description paragraph 'Track and manage bugs' (block-11-2)
            if block_id == "block-11-2" or (block_type == "paragraph" and "track and manage bugs" in content_lower):
                description_paragraph_idx = idx
        
            # Find 'Search results not updating in real-time' todo (block-11-8)
            if block_id == "block-11-8" or (block_type == "todo" and "search results not updating in real-time" in content_lower):
                search_results_todo_idx = idx
        
            # Find 'Low Priority' heading (block-11-9)
            if block_id == "block-11-9" or (block_type == "heading2" and "low priority" in content_lower):
                low_priority_heading_idx = idx
        
            # Find the new '⚡ Performance Issues' heading
            if block_type == "heading2" and "performance issues" in content_lower:
                performance_heading_idx = idx
        
            # Find the status callout (should be at the top with '📈' icon)
            if block_type == "callout" and "bug status" in content_lower:
                status_callout_idx = idx
    
        # Validation: ensure we found the reference points
        if main_heading_idx is None:
            errors.append("[X] Main 'Bug Tracker' heading (heading1) not found")
        else:
            checks_passed.append("[C] Main 'Bug Tracker' heading (heading1) found")
    
        if description_paragraph_idx is None:
            errors.append("[X] Description paragraph 'Track and manage bugs...' not found")
        else:
            checks_passed.append("[C] Description paragraph 'Track and manage bugs...' found")
    
        if search_results_todo_idx is None:
            errors.append("[X] 'Search results not updating in real-time' todo not found")
        else:
            checks_passed.append("[C] 'Search results updating in real-time' todo found")
    
        if low_priority_heading_idx is None:
            errors.append("[X] 'Low Priority' heading not found")
        else:
            checks_passed.append("[C] 'Low Priority' heading found")
    
        # 4. Verify heading_2 '⚡ Performance Issues' exists in the correct position
        if performance_heading_idx is None:
            errors.append("[X] heading_2 '⚡ Performance Issues' not found")
        else:
            checks_passed.append("[C] heading_2 '⚡ Performance Issues' found")
    
        performance_block = page_blocks_sorted[performance_heading_idx]
        performance_content = performance_block.get("content", "")
    
        # Verify position: must be AFTER 'Search results not updating' and BEFORE 'Low Priority'
        if performance_heading_idx <= search_results_todo_idx:
            errors.append(f"[X] '⚡ Performance Issues' heading must appear AFTER 'Search results not updating in real-time' todo (found at index {performance_heading_idx}, todo at {search_results_todo_idx})")
        else:
            checks_passed.append(f"[C] '⚡ Performance Issues' heading must appear AFTER 'Search results updating in real-time' todo (found at index {performance_heading_idx}, todo at {search_results_todo_idx})")
    
        if performance_heading_idx >= low_priority_heading_idx:
            errors.append(f"[X] '⚡ Performance Issues' heading must appear BEFORE 'Low Priority' heading (found at index {performance_heading_idx}, 'Low Priority' at {low_priority_heading_idx})")
        else:
            checks_passed.append(f"[C] '⚡ Performance Issues' heading must appear BEFORE 'Low Priority' heading (found at index {performance_heading_idx}, 'Low Priority' at {low_priority_heading_idx})")
    
        # 5. Verify the three required todo blocks exist after the Performance Issues heading
        required_todos = [
            "🔧 Memory leak in dashboard view",
            "📊 Slow query performance on reports page",
            "🚦 API response time exceeding 2 seconds"
        ]
    
        # Get blocks between Performance Issues heading and Low Priority heading
        blocks_after_performance = page_blocks_sorted[performance_heading_idx + 1:low_priority_heading_idx]
    
        # Find all todos in this range
        todos_after_performance = [b for b in blocks_after_performance if b.get("type") == "todo"]
    
        if len(todos_after_performance) < 3:
            errors.append(f"[X] Expected at least 3 todo blocks under '⚡ Performance Issues', found {len(todos_after_performance)}")
        else:
            checks_passed.append(f"[C] Found at least 3 todo blocks under '⚡ Performance Issues' ({len(todos_after_performance)})")
    
        # Verify each required todo exists with exact text and is unchecked
        for required_todo in required_todos:
            found = False
            for todo_block in todos_after_performance:
                todo_content = todo_block.get("content", "")
                if required_todo in todo_content or todo_content in required_todo:
                    # Verify it's unchecked
                    is_checked = todo_block.get("properties", {}).get("checked", False)
                    if is_checked:
                        errors.append(f"[X] Todo '{required_todo}' should be unchecked but is checked")
                    else:
                        checks_passed.append(f"[C] Todo '{required_todo}' should be unchecked but is checked")
                    found = True
                    break
        
            if not found:
                errors.append(f"[X] Required todo '{required_todo}' not found under '⚡ Performance Issues'")
            else:
                checks_passed.append(f"[C] Required todo '{required_todo}' found under '⚡ Performance Issues'")
    
        # 6. Verify the status callout exists at the top of the page
        if status_callout_idx is None:
            errors.append("[X] Status callout with 'Bug Status:' not found at the top of the page")
        else:
            checks_passed.append("[C] Status callout with 'Bug Status:' found at the top of the page")
    
        # Verify callout position: must be AFTER main heading and BEFORE description paragraph
        if status_callout_idx <= main_heading_idx:
            errors.append(f"[X] Status callout must appear AFTER 'Bug Tracker' heading (callout at index {status_callout_idx}, heading at {main_heading_idx})")
        else:
            checks_passed.append(f"[C] Status callout must appear AFTER 'Bug Tracker' heading (callout at index {status_callout_idx}, heading at {main_heading_idx})")
    
        if status_callout_idx >= description_paragraph_idx:
            errors.append(f"[X] Status callout must appear BEFORE description paragraph (callout at index {status_callout_idx}, paragraph at {description_paragraph_idx})")
        else:
            checks_passed.append(f"[C] Status callout must appear BEFORE description paragraph (callout at index {status_callout_idx}, paragraph at {description_paragraph_idx})")
    
        # 7. Verify callout properties
        status_callout = page_blocks_sorted[status_callout_idx]
        callout_content = status_callout.get("content", "")
        callout_props = status_callout.get("properties", {})
        callout_bg = callout_props.get("backgroundColor", "")
        callout_icon = callout_props.get("icon", "")
    
        # Verify blue_background
        if "blue" not in callout_bg.lower():
            errors.append(f"[X] Status callout should have blue_background, found '{callout_bg}'")
        else:
            checks_passed.append(f"[C] Status callout should have blue_background, found '{callout_bg}'")
    
        # Verify 📈 icon
        if "📈" not in callout_icon:
            errors.append(f"[X] Status callout should have '📈' icon, found '{callout_icon}'")
        else:
            checks_passed.append(f"[C] Status callout should have '📈' icon, found '{callout_icon}'")
    
        # 8. Verify callout content with correct metrics
        callout_content_lower = callout_content.lower()
    
        if "bug status" not in callout_content_lower:
            errors.append(f"[X] Callout should contain 'Bug Status:', found '{callout_content}'")
        else:
            checks_passed.append(f"[C] Callout should contain 'Bug Status:', found '{callout_content}'")
    
        # Check for total issues count
        if f"{total_todos} total issues" not in callout_content_lower and f"{total_todos} total" not in callout_content_lower:
            errors.append(f"[X] Callout should contain '{total_todos} total issues', found '{callout_content}'")
        else:
            checks_passed.append(f"[C] Callout should contain '{total_todos} total issues', found '{callout_content}'")
    
        # Check for resolved count
        if f"{resolved_todos} resolved" not in callout_content_lower:
            errors.append(f"[X] Callout should contain '{resolved_todos} resolved', found '{callout_content}'")
        else:
            checks_passed.append(f"[C] Callout should contain '{resolved_todos} resolved', found '{callout_content}'")
    
        # Check for completion rate percentage
        if f"{completion_rate}%" not in callout_content:
            errors.append(f"[X] Callout should contain '{completion_rate}%' completion rate, found '{callout_content}'")
        else:
            checks_passed.append(f"[C] Callout should contain '{completion_rate}%' completion rate, found '{callout_content}'")
    
        # All validations passed
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

    # -----------------------------------------------------------------------------
    # Task: engineering-wiki-documentation-coverage
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_engineering_wiki_documentation_coverage(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate documentation coverage restructuring on Engineering Wiki page.
    
    Goal: Analyze heading_3 sections, add callouts for empty sections, dividers for 
    documented sections, and create a coverage report.
    
    Validation steps:
    1. Find the 'Engineering Wiki' page (page-4)
    2. Get all blocks for this page sorted by order
    3. Identify all heading_3 blocks and determine which have content after them
    4. For heading_3 blocks WITHOUT content: verify red callout with ⚠️ icon added
    5. For heading_3 blocks WITH content: verify divider added at end of section
    6. Verify heading_2 '📝 Documentation Coverage Report' exists at end
    7. Verify coverage paragraph with accurate counts and percentage
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    
    # 1. Find the Engineering Wiki page
    try:
        wiki_page = _find_page_by_title(final_state_backend, "Engineering Wiki")
        if not wiki_page:
            errors.append("[X] Engineering Wiki page not found")
        else:
            checks_passed.append("[C] Engineering Wiki page found")
    
        page_id = wiki_page.get("_id")
    
        # 2. Get all blocks for this page sorted by order
        all_blocks = final_state_backend.query({
            "collection": "blocks",
            "filter": {"pageId": page_id}
        })
        page_blocks = [b for b in all_blocks if b.get("pageId") == page_id]
        page_blocks_sorted = sorted(page_blocks, key=lambda b: b.get("order", 0))
    
        if not page_blocks_sorted:
            errors.append("[X] No blocks found on the Engineering Wiki page")
        else:
            checks_passed.append("[C] blocks found on the Engineering Wiki page")
    
        # 3. Identify all heading_3 blocks and determine which have content after them
        heading3_blocks = []
        for idx, block in enumerate(page_blocks_sorted):
            if block.get("type") == "heading3":
                heading3_blocks.append((idx, block))
    
        if not heading3_blocks:
            errors.append("[X] No heading_3 blocks found on the page")
        else:
            checks_passed.append("[C] heading_3 blocks found on the page")
    
        # Analyze each heading_3 section
        documented_sections = 0
        empty_sections = 0
    
        for i, (heading_idx, heading_block) in enumerate(heading3_blocks):
            heading_order = heading_block.get("order", 0)
            heading_content = heading_block.get("content", "")
        
            # Find the next heading (any level) to determine section boundary
            next_heading_order = None
            for block in page_blocks_sorted:
                block_order = block.get("order", 0)
                if block_order > heading_order:
                    block_type = block.get("type", "")
                    if block_type in ["heading1", "heading2", "heading3"]:
                        next_heading_order = block_order
                        break
        
            # Get all blocks in this section (between this heading and next heading)
            section_blocks = []
            for block in page_blocks_sorted:
                block_order = block.get("order", 0)
                if block_order > heading_order:
                    if next_heading_order is None or block_order < next_heading_order:
                        section_blocks.append(block)
                    else:
                        break
        
            # Check for content blocks (paragraph or list)
            content_blocks = [
                b for b in section_blocks 
                if b.get("type") in ["paragraph", "bulletedList", "numberedList"]
            ]
        
            # Check for callout blocks (warning callouts)
            callout_blocks = [
                b for b in section_blocks 
                if b.get("type") == "callout"
            ]
        
            # Check for divider blocks
            divider_blocks = [
                b for b in section_blocks 
                if b.get("type") == "divider"
            ]
        
            # Determine if section was originally empty or documented
            has_warning_callout = False
            for callout in callout_blocks:
                props = callout.get("properties", {})
                bg_color = props.get("backgroundColor", "")
                icon = props.get("icon", "")
                callout_content = callout.get("content", "")
            
                if ("red" in bg_color.lower() and 
                    "⚠️" in icon and 
                    "Section requires content" in callout_content and
                    "please add documentation" in callout_content.lower()):
                    has_warning_callout = True
                    break
        
            has_divider = len(divider_blocks) > 0
            has_actual_content = len(content_blocks) > 0
        
            if has_warning_callout:
                # This was an empty section
                empty_sections += 1
            elif has_actual_content and has_divider:
                # This was a documented section
                documented_sections += 1
            elif has_actual_content and not has_divider:
                errors.append(f"[X] heading_3 '{heading_content}' has content but missing divider at end of section")
            elif not has_actual_content and not has_warning_callout:
                errors.append(f"[X] heading_3 '{heading_content}' has no content but missing red warning callout")
            else:
                checks_passed.append(f"[C] heading_3 '{heading_content}' has content but has red warning callout")
    
        total_sections = documented_sections + empty_sections
    
        if total_sections == 0:
            errors.append("[X] No heading_3 sections could be analyzed")
        else:
            checks_passed.append("[C] heading_3 sections could be analyzed")
    
        # Calculate expected coverage percentage
        expected_coverage = int((documented_sections / total_sections) * 100) if total_sections > 0 else 0
    
        # 6. Verify heading_2 '📝 Documentation Coverage Report' exists
        report_heading = None
        for block in page_blocks_sorted:
            if block.get("type") == "heading2":
                content = block.get("content", "")
                if "Documentation Coverage Report" in content and "📝" in content:
                    report_heading = block
                    break
    
        if not report_heading:
            errors.append("[X] Missing heading_2 '📝 Documentation Coverage Report'")
        else:
            checks_passed.append("[C] has heading_2 '📝 Documentation Coverage Report'")
    
        report_order = report_heading.get("order", 0)
    
        # 7. Verify coverage paragraph with accurate counts
        coverage_paragraph = None
        for block in page_blocks_sorted:
            block_order = block.get("order", 0)
            if block_order > report_order and block.get("type") == "paragraph":
                coverage_paragraph = block
                break
    
        if not coverage_paragraph:
            errors.append("[X] Missing coverage paragraph after '📝 Documentation Coverage Report' heading")
        else:
            checks_passed.append("[C] has coverage paragraph after '📝 Documentation Coverage Report' heading")
    
        coverage_content = coverage_paragraph.get("content", "")
    
        if f"Documented sections: {documented_sections}" not in coverage_content:
            errors.append(f"[X] Coverage paragraph should contain Documented sections: {documented_sections},  got: {coverage_content}")
        else:
            checks_passed.append(f"[C] Coverage paragraph should contain Documented sections: {documented_sections}, got: {coverage_content}")
    
        if f"Empty sections: {empty_sections}" not in coverage_content:
            errors.append(f"[X] Coverage paragraph should contain Empty sections: {empty_sections},  got: {coverage_content}")
        else:
            checks_passed.append(f"[C] Coverage paragraph should contain Empty sections: {empty_sections}, got: {coverage_content}")
    
        if f"Coverage: {expected_coverage}%" not in coverage_content:
            errors.append(f"[X] Coverage paragraph should contain Coverage: {expected_coverage}%,  got: {coverage_content}")
        else:
            checks_passed.append(f"[C] Coverage paragraph should contain Coverage: {expected_coverage}%, got: {coverage_content}")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

    # -----------------------------------------------------------------------------
    # Task: engineering-resource-hub-v2
    # Goal: Create an engineering resource hub page with code library statistics and quick links.
    # 
    # Validation steps (ordered):
    # 1. Find 'Engineering Wiki' page (page-4) and verify new page is a child of it
    # 2. Verify new page titled '🔧 Engineering Resource Hub' exists
    # 3. Fetch 'Code Examples Repository' page (page-20) and count code blocks by language
    # 4. Verify page structure:
    #    - heading_1: '🔧 Engineering Resource Hub'
    #    - heading_2: '💻 Code Library Statistics'
    #    - callout with purple_background, no icon, containing bulleted list with accurate counts
    #    - heading_2: '🔗 Quick Links'
    #    - 3 bookmark blocks with exact URLs and captions
    #    - divider
    #    - quote block with exact text
    # 
    # Weights: All checks pass = 1.0, any failure = 0.0
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_engineering_resource_hub(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate engineering resource hub page creation.
    
    Success criteria:
    1. Page '🔧 Engineering Resource Hub' exists as child of 'Engineering Wiki'
    2. Code block counts from 'Code Examples Repository' are accurate
    3. Page structure matches exact requirements:
       - heading_1 '🔧 Engineering Resource Hub'
       - heading_2 '💻 Code Library Statistics'
       - callout (purple_background, no icon) with bulleted list of counts
       - heading_2 '🔗 Quick Links'
       - 3 bookmarks with exact URLs and captions
       - divider
       - quote 'Code is poetry written in logic.'
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    
    # 1. Find Engineering Wiki page
    try:
        engineering_wiki = _find_page_by_title(final_state_backend, "Engineering Wiki")
        if not engineering_wiki:
            errors.append("[X] Engineering Wiki page not found")
        else:
            checks_passed.append("[C] Engineering Wiki page found")
    
        # 2. Find the new Engineering Resource Hub page
        resource_hub = _find_page_by_title(final_state_backend, "🔧 Engineering Resource Hub")
        if not resource_hub:
            errors.append("[X] '🔧 Engineering Resource Hub' page not found")
        else:
            checks_passed.append("[C] '🔧 Engineering Resource Hub' page found")
    
        # 3. Verify it's a child of Engineering Wiki
        if not _check_page_is_child_of(engineering_wiki, resource_hub):
            errors.append("[X] '🔧 Engineering Resource Hub' is not a child of 'Engineering Wiki'")
        else:
            checks_passed.append("[C] '🔧 Engineering Resource Hub' is a child of 'Engineering Wiki'")
    
        # 4. Get Code Examples Repository page and count code blocks by language
        code_examples_page = _find_page_by_title(final_state_backend, "Code Examples Repository")
        if not code_examples_page:
            errors.append("[X] Code Examples Repository page not found")
        else:
            checks_passed.append("[C] Code Examples Repository page found")
    
        code_examples_blocks = _get_blocks_for_page(final_state_backend, code_examples_page.get("_id"))
    
        # Count code blocks by language
        code_blocks = [b for b in code_examples_blocks if b.get("type") == "code"]
        total_code = len(code_blocks)
    
        language_counts = {}
        for block in code_blocks:
            props = block.get("properties", {})
            lang = props.get("language", "unknown")
            language_counts[lang] = language_counts.get(lang, 0) + 1
    
        js_count = language_counts.get("javascript", 0)
        py_count = language_counts.get("python", 0)
        ts_count = language_counts.get("typescript", 0)
    
        # 5. Get blocks from the new page and validate structure
        hub_blocks = _get_blocks_for_page(final_state_backend, resource_hub.get("_id"))
        if not hub_blocks:
            errors.append("[X] No blocks found on '🔧 Engineering Resource Hub' page")
        else:
            checks_passed.append("[C] blocks found on '🔧 Engineering Resource Hub' page")
    
        # Sort blocks by order
        hub_blocks_sorted = sorted(hub_blocks, key=lambda b: b.get("order", 0))
    
        block_idx = 0
    
        # Check heading_1: '🔧 Engineering Resource Hub'
        if block_idx >= len(hub_blocks_sorted):
            errors.append("[X] Missing heading_1 block")
        else:
            checks_passed.append("[C] has heading_1 block")
        h1_block = hub_blocks_sorted[block_idx]
        if h1_block.get("type") != "heading1":
            errors.append(f"[X] First block should be heading1, got {h1_block.get('type')}")
        else:
            checks_passed.append(f"[C] First block should be heading1, got {h1_block.get('type')}")
        if "engineering resource hub" not in h1_block.get("content", "").lower():
            errors.append("[X] heading_1 should contain 'Engineering Resource Hub'")
        else:
            checks_passed.append("[C] heading_1 should contain 'Engineering Resource Hub'")
        block_idx += 1
    
        # Check heading_2: '💻 Code Library Statistics'
        if block_idx >= len(hub_blocks_sorted):
            errors.append("[X] Missing heading_2 '💻 Code Library Statistics'")
        else:
            checks_passed.append("[C] has heading_2 '💻 Code Library Statistics'")
        h2_stats = hub_blocks_sorted[block_idx]
        if h2_stats.get("type") != "heading2":
            errors.append(f"[X] Second block should be heading2, got {h2_stats.get('type')}")
        else:
            checks_passed.append(f"[C] Second block should be heading2, got {h2_stats.get('type')}")
        if "code library statistics" not in h2_stats.get("content", "").lower():
            errors.append("[X] heading_2 should contain 'Code Library Statistics'")
        else:
            checks_passed.append("[C] heading_2 should contain 'Code Library Statistics'")
        block_idx += 1
    
        # Check callout block (purple_background, no icon)
        if block_idx >= len(hub_blocks_sorted):
            errors.append("[X] Missing callout block for statistics")
        else:
            checks_passed.append("[C] has callout block for statistics")
        callout_block = hub_blocks_sorted[block_idx]
        if callout_block.get("type") != "callout":
            errors.append(f"[X] Third block should be callout, got {callout_block.get('type')}")
        else:
            checks_passed.append(f"[C] Third block should be callout, got {callout_block.get('type')}")
    
        callout_props = callout_block.get("properties", {})
        callout_bg = callout_props.get("backgroundColor", "")
        if "purple" not in callout_bg.lower():
            errors.append(f"[X] Callout should have purple_background, got '{callout_bg}'")
        else:
            checks_passed.append(f"[C] Callout should have purple_background, got '{callout_bg}'")
    
        # Check that icon is empty/not set (no icon)
        callout_icon = callout_props.get("icon", "")
        if callout_icon and callout_icon.strip():
            errors.append(f"[X] Callout should have no icon, but found icon: '{callout_icon}'")
        else:
            checks_passed.append(f"[C] Callout should have icon, but found icon: '{callout_icon}'")
    
        # Check callout content contains accurate counts
        callout_content = callout_block.get("content", "").lower()
    
        # Verify total count
        if f"total code examples: {total_code}" not in callout_content:
            errors.append(f"[X] Callout should contain 'Total code examples: {total_code}'")
        else:
            checks_passed.append(f"[C] Callout should contain 'Total code examples: {total_code}'")
    
        # Verify JavaScript count
        if f"javascript examples: {js_count}" not in callout_content:
            errors.append(f"[X] Callout should contain 'JavaScript examples: {js_count}'")
        else:
            checks_passed.append(f"[C] Callout should contain 'JavaScript examples: {js_count}'")
    
        # Verify Python count
        if f"python examples: {py_count}" not in callout_content:
            errors.append(f"[X] Callout should contain 'Python examples: {py_count}'")
        else:
            checks_passed.append(f"[C] Callout should contain 'Python examples: {py_count}'")
    
        # Verify TypeScript count
        if f"typescript examples: {ts_count}" not in callout_content:
            errors.append(f"[X] Callout should contain 'TypeScript examples: {ts_count}'")
        else:
            checks_passed.append(f"[C] Callout should contain 'TypeScript examples: {ts_count}'")
    
        block_idx += 1
    
        # Check heading_2: '🔗 Quick Links'
        if block_idx >= len(hub_blocks_sorted):
            errors.append("[X] Missing heading_2 '🔗 Quick Links'")
        else:
            checks_passed.append("[C] has heading_2 '🔗 Quick Links'")
        h2_links = hub_blocks_sorted[block_idx]
        if h2_links.get("type") != "heading2":
            errors.append(f"[X] Block should be heading2 for Quick Links, got {h2_links.get('type')}")
        else:
            checks_passed.append(f"[C] Block should be heading2 for Quick Links, got {h2_links.get('type')}")
        if "quick links" not in h2_links.get("content", "").lower():
            errors.append("[X] heading_2 should contain 'Quick Links'")
        else:
            checks_passed.append("[C] heading_2 should contain 'Quick Links'")
        block_idx += 1
    
        # Check 3 bookmark blocks with exact URLs and captions
        expected_bookmarks = [
            {"url": "https://github.com/acmecorp", "caption": "Company GitHub"},
            {"url": "https://docs.acmecorp.com/api", "caption": "API Documentation"},
            {"url": "https://status.acmecorp.com", "caption": "System Status"},
        ]
    
        found_bookmarks = []
    
        # Collect all bookmark blocks starting from current position
        for i in range(block_idx, len(hub_blocks_sorted)):
            block = hub_blocks_sorted[i]
            if block.get("type") == "bookmark":
                found_bookmarks.append(block)
                block_idx = i + 1
            elif block.get("type") in ["divider", "quote"]:
                break
    
        if len(found_bookmarks) < 3:
            errors.append(f"[X] Expected 3 bookmark blocks, found {len(found_bookmarks)}")
        else:
            checks_passed.append(f"[C] Found 3 bookmark blocks as expected")
    
        # Validate each expected bookmark exists
        for expected in expected_bookmarks:
            found = False
            expected_url = expected["url"].lower()
            expected_caption = expected["caption"].lower()
        
            for bookmark in found_bookmarks:
                props = bookmark.get("properties", {})
                url = props.get("url", "").lower()
                caption = props.get("caption", "").lower()
            
                if expected_url in url and expected_caption in caption:
                    found = True
                    break
        
            if not found:
                errors.append(f"[X] Missing bookmark: URL='{expected['url']}', caption='{expected['caption']}'")
            else:
                checks_passed.append(f"[C] has bookmark: URL='{expected['url']}', caption='{expected['caption']}'")
    
        # Check divider
        divider_found = False
        divider_idx = None
        for i in range(block_idx, len(hub_blocks_sorted)):
            block = hub_blocks_sorted[i]
            if block.get("type") == "divider":
                divider_found = True
                divider_idx = i
                break
    
        if not divider_found:
            errors.append("[X] Missing divider block")
        else:
            checks_passed.append("[C] has divider block")
    
        # Check quote block after divider
        quote_found = False
        expected_quote = "code is poetry written in logic"
    
        for i in range(divider_idx + 1, len(hub_blocks_sorted)):
            block = hub_blocks_sorted[i]
            if block.get("type") == "quote":
                quote_content = block.get("content", "").lower()
                if expected_quote in quote_content:
                    quote_found = True
                    break
    
        if not quote_found:
            errors.append("[X] Missing quote block with text 'Code is poetry written in logic.'")
        else:
            checks_passed.append("[C] has quote block with text 'Code is poetry written in logic.'")
    
        # All validations passed
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

    # -----------------------------------------------------------------------------
    # Task: team-directory-skills-matrix
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_team_directory_skills_matrix(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate skills matrix system implementation on Team Directory page.
    
    Goal: Implement a comprehensive skills matrix system with:
    1. Skills Matrix heading and legend callout at the beginning
    2. Skills section with 4 skill items for each team member
    3. Summary section at the end
    
    Validation steps:
    1. Find Team Directory page (page-8)
    2. Verify heading_2 '🎯 Team Skills Matrix' appears after main title
    3. Verify purple callout with '💡' icon and skills categorization text
    4. For each team member (Alice Chen, Bob Martinez, Frank Zhang, Carol Williams):
       - Verify heading_3 '💼 Skills & Expertise' after their entry
       - Verify 4 bulletedList items with exact skill ratings
    5. Verify divider after all team members
    6. Verify heading_2 '📊 Skill Distribution Summary'
    7. Verify paragraph with team strengths text
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    
    # 1. Find Team Directory page
    try:
        team_directory = _find_page_by_title(final_state_backend, "Team Directory")
        if not team_directory:
            errors.append("[X] Team Directory page not found")
        else:
            checks_passed.append("[C] Team Directory page found")
    
        page_id = team_directory.get("_id")
    
        # 2. Get all blocks for this page sorted by order
        all_blocks = final_state_backend.query({
            "collection": "blocks",
            "filter": {"pageId": page_id}
        })
        page_blocks = [b for b in all_blocks if b.get("pageId") == page_id]
        page_blocks_sorted = sorted(page_blocks, key=lambda b: b.get("order", 0))
    
        if not page_blocks_sorted:
            errors.append("[X] No blocks found on Team Directory page")
        else:
            checks_passed.append("[C] blocks found on Team Directory page")
    
        # 3. Find the main title (heading1 "Team Directory")
        main_title_idx = None
        for idx, block in enumerate(page_blocks_sorted):
            if block.get("type") == "heading1" and "team directory" in block.get("content", "").lower():
                main_title_idx = idx
                break
    
        if main_title_idx is None:
            errors.append("[X] Main title 'Team Directory' (heading1) not found")
        else:
            checks_passed.append("[C] Main title 'Team Directory' (heading1) found")
    
        # 4. Verify heading_2 '🎯 Team Skills Matrix' appears after main title
        skills_matrix_heading = None
        skills_matrix_idx = None
        for idx, block in enumerate(page_blocks_sorted[main_title_idx + 1:], start=main_title_idx + 1):
            block_type = block.get("type", "")
            if block_type in ["heading2", "heading_2"]:
                content = block.get("content", "")
                if "team skills matrix" in content.lower() and "🎯" in content:
                    skills_matrix_heading = block
                    skills_matrix_idx = idx
                    break
    
        if not skills_matrix_heading:
            errors.append("[X] heading_2 '🎯 Team Skills Matrix' not found after main title")
        else:
            checks_passed.append("[C] heading_2 '🎯 Team Skills Matrix' found after main title")
    
        # 5. Verify purple callout with '💡' icon appears after Skills Matrix heading
        skills_callout = None
        for idx, block in enumerate(page_blocks_sorted[skills_matrix_idx + 1:], start=skills_matrix_idx + 1):
            if block.get("type") == "callout":
                props = block.get("properties", {})
                bg_color = props.get("backgroundColor", "")
                icon = props.get("icon", "")
                content = block.get("content", "")
            
                if (bg_color in ["purple", "purple_background"] and 
                    "💡" in icon and 
                    "skills are categorized as" in content.lower()):
                    # Verify the content has the star ratings
                    if "expert" in content.lower() and "⭐⭐⭐" in content:
                        if "proficient" in content.lower() and "⭐⭐" in content:
                            if "learning" in content.lower() and props.get("icon") == "⭐":
                                skills_callout = block
                                break
    
        if not skills_callout:
            errors.append("[X] Purple callout with '💡' icon and skills categorization text not found. Expected: purple_background, icon '💡', content containing 'Skills are categorized as: Expert (⭐⭐⭐), Proficient (⭐⭐), Learning (⭐)'")
        else:
            checks_passed.append("[C] Purple callout with '💡' icon and skills categorization text found. Expected: purple_background, icon '💡', content containing 'Skills are categorized as: Expert (⭐⭐⭐), Proficient (⭐⭐), Learning (⭐)'")
    
        # 6. Define team members to check
        team_members = [
            "Alice Chen",
            "Bob Martinez",
            "Frank Zhang",
            "Carol Williams"
        ]
    
        required_skills = [
            "Frontend Development: ⭐⭐⭐",
            "Backend Development: ⭐⭐",
            "DevOps: ⭐",
            "UI/UX Design: ⭐⭐"
        ]
    
        # 7. For each team member, verify skills section
        for member in team_members:
            # Find the team member's bullet entry
            member_idx = None
            for idx, block in enumerate(page_blocks_sorted):
                if block.get("type") == "bulletedList":
                    content = block.get("content", "")
                    if member.lower() in content.lower():
                        member_idx = idx
                        break
        
            if member_idx is None:
                errors.append(f"[X] Team member entry for '{member}' not found")
            else:
                checks_passed.append(f"[C] Team member entry for '{member}' found")
        
            # Look for heading_3 '💼 Skills & Expertise' after the member entry
            skills_heading_found = False
            skills_heading_idx = None
        
            for idx, block in enumerate(page_blocks_sorted[member_idx + 1:], start=member_idx + 1):
                block_type = block.get("type", "")
                content = block.get("content", "").lower()
            
                # Stop if we hit another team member entry or a team section heading
                if block_type == "bulletedList":
                    # Check if this is another team member
                    for other_member in team_members:
                        if other_member.lower() in block.get("content", "").lower() and other_member != member:
                            break
            
                if block_type in ["heading3", "heading_3"]:
                    if "skills & expertise" in content and "💼" in block.get("content", ""):
                        skills_heading_found = True
                        skills_heading_idx = idx
                        break
            
                # Stop if we hit a heading2 (next section)
                if block_type in ["heading2", "heading_2"] and "engineering team" not in content and "design team" not in content:
                    break
        
            if not skills_heading_found:
                errors.append(f"[X] heading_3 '💼 Skills & Expertise' not found after team member '{member}'")
            else:
                checks_passed.append(f"[C] heading_3 '💼 Skills & Expertise' found after team member '{member}'")
        
            # Verify 4 bulletedList items with exact skills after the skills heading
            skills_found = []
            for idx, block in enumerate(page_blocks_sorted[skills_heading_idx + 1:], start=skills_heading_idx + 1):
                block_type = block.get("type", "")
            
                # Stop if we hit a non-bulletedList block (except for first few)
                if block_type != "bulletedList" and len(skills_found) >= 4:
                    break
            
                if block_type == "bulletedList":
                    content = block.get("content", "")
                    # Check for each required skill
                    for skill in required_skills:
                        # Flexible matching - check key parts
                        skill_name = skill.split(":")[0].strip().lower()
                        skill_stars = skill.split(":")[1].strip() if ":" in skill else ""
                    
                        if skill_name in content.lower() and skill_stars in content:
                            if skill not in skills_found:
                                skills_found.append(skill)
            
                # Stop if we've found enough or hit a different block type
                if len(skills_found) >= 4:
                    break
            
                # Stop at next heading or divider
                if block_type in ["heading2", "heading_2", "heading3", "heading_3", "divider"]:
                    break
        
            if len(skills_found) < 4:
                missing_skills = [s for s in required_skills if s not in skills_found]
                errors.append(f"[X] Missing skill items for '{member}'. Expected 4 skills, found {len(skills_found)}. Missing: {missing_skills}")
            else:
                checks_passed.append(f"[C] has skill items for '{member}'. Found 4 skills as expected")
    
        # 8. Verify divider after all team members
        divider_found = False
        divider_idx = None
    
        for idx, block in enumerate(page_blocks_sorted):
            if block.get("type") == "divider":
                # Check if there's a summary heading after it
                for next_block in page_blocks_sorted[idx + 1:]:
                    next_type = next_block.get("type", "")
                    next_content = next_block.get("content", "").lower()
                    if next_type in ["heading2", "heading_2"] and "skill distribution summary" in next_content:
                        divider_found = True
                        divider_idx = idx
                        break
                if divider_found:
                    break
    
        if not divider_found:
            errors.append("[X] Divider not found before '📊 Skill Distribution Summary' heading")
        else:
            checks_passed.append("[C] Divider found before '📊 Skill Distribution Summary' heading")
    
        # 9. Verify heading_2 '📊 Skill Distribution Summary' after divider
        summary_heading = None
        for block in page_blocks_sorted[divider_idx + 1:]:
            block_type = block.get("type", "")
            if block_type in ["heading2", "heading_2"]:
                content = block.get("content", "")
                if "skill distribution summary" in content.lower() and "📊" in content:
                    summary_heading = block
                    break
    
        if not summary_heading:
            errors.append("[X] heading_2 '📊 Skill Distribution Summary' not found after divider")
        else:
            checks_passed.append("[C] heading_2 '📊 Skill Distribution Summary' found after divider")
    
        # 10. Verify paragraph with team strengths text
        summary_heading_idx = page_blocks_sorted.index(summary_heading)
        summary_paragraph = None
    
        for block in page_blocks_sorted[summary_heading_idx + 1:]:
            if block.get("type") == "paragraph":
                content = block.get("content", "").lower()
                # Check for key phrases
                if ("team strengths" in content and 
                    "frontend" in content and 
                    "backend" in content and
                    "growing areas" in content):
                    summary_paragraph = block
                    break
    
        if not summary_paragraph:
            errors.append("[X] Summary paragraph not found. Expected text containing: 'Team strengths: Frontend (3 experts), Backend (2 experts), Growing areas: DevOps, Design'")
        else:
            checks_passed.append("[C] Summary paragraph found. Expected text containing: 'Team strengths: Frontend (3 experts), Backend (2 experts), Growing areas: DevOps, Design'")
    
        # Verify specific content in summary paragraph
        summary_content = summary_paragraph.get("content", "")
        if "3 experts" not in summary_content.lower() or "2 experts" not in summary_content.lower():
            errors.append(f"[X] Summary paragraph missing expert counts. Expected '3 experts' and '2 experts', got: '{summary_content}'")
        else:
            checks_passed.append(f"[C] Summary paragraph has expert counts. Expected '3 experts' and '2 experts', got: '{summary_content}'")
    
        if "devops" not in summary_content.lower() or "design" not in summary_content.lower():
            errors.append(f"[X] Summary paragraph missing growing areas. Expected 'DevOps' and 'Design', got: '{summary_content}'")
        else:
            checks_passed.append(f"[C] Summary paragraph has growing areas. Expected 'DevOps' and 'Design', got: '{summary_content}'")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

    # -----------------------------------------------------------------------------
    # Task: feature-tracking-dashboard
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_feature_tracking_dashboard(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Feature Tracking Dashboard on Feature Requests page.
    
    Goal: Transform the Feature Requests page into a comprehensive feature tracking
    system with statistics and sprint candidates.
    
    Validation steps (ordered):
    1. Find the Feature Requests page
    2. Find the intro paragraph "Community requested features organized by priority."
    3. Find the "High Priority" heading
    4. Verify heading_2 '🎯 Feature Implementation Dashboard' exists AFTER intro paragraph 
       but BEFORE High Priority heading
    5. Verify blue callout with 📊 icon exists with 'Feature Pipeline Status' text
    6. Verify bulletedList items with correct statistics:
       - 'Total Features Requested: 3'
       - 'Implemented: 1 (33.33%)'
       - 'In Pipeline: 2 (66.67%)'
    7. Find 'Community Suggestions' section and the last bulletedList item 'Advanced search filters'
    8. Verify heading_3 '🚀 Next Sprint Candidates' appears after last bulleted item
    9. Verify numberedList with unchecked todo texts:
       - 'Keyboard shortcuts customization'
       - 'Export to PDF functionality'
    
    Weights: All-or-nothing (1.0 if all pass, 0.0 otherwise)
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    
    # 1. Find the Feature Requests page
    try:
        feature_page = _find_page_by_title(final_state_backend, "Feature Requests")
        if not feature_page:
            errors.append("[X] Feature Requests page not found")
        else:
            checks_passed.append("[C] Feature Requests page found")
    
        page_id = feature_page.get("_id")
        page_blocks = _get_blocks_for_page(final_state_backend, page_id)
    
        if not page_blocks:
            errors.append("[X] No blocks found on Feature Requests page")
        else:
            checks_passed.append("[C] blocks found on Feature Requests page")
    
        # Sort blocks by order
        page_blocks_sorted = sorted(page_blocks, key=lambda b: b.get("order", 0))
    
        # 2. Find key reference points
        intro_paragraph_idx = None
        high_priority_idx = None
        dashboard_heading_idx = None
        community_suggestions_idx = None
        advanced_search_idx = None
        next_sprint_idx = None
    
        for idx, block in enumerate(page_blocks_sorted):
            content = block.get("content", "")
            content_lower = content.lower()
            block_type = block.get("type", "")
        
            if block_type == "paragraph" and "community requested features organized by priority" in content_lower:
                intro_paragraph_idx = idx
            elif block_type == "heading2" and "high priority" in content_lower:
                high_priority_idx = idx
            elif block_type == "heading2" and "feature implementation dashboard" in content_lower:
                dashboard_heading_idx = idx
            elif block_type == "heading2" and "community suggestions" in content_lower:
                community_suggestions_idx = idx
            elif block_type == "bulletedList" and "advanced search filters" in content_lower:
                advanced_search_idx = idx
            elif block_type == "heading3" and "next sprint candidates" in content_lower:
                next_sprint_idx = idx
    
        # 3. Verify intro paragraph exists
        if intro_paragraph_idx is None:
            errors.append("[X] Intro paragraph 'Community requested features organized by priority.' not found")
        else:
            checks_passed.append("[C] Intro paragraph 'Community requested features organized by priority.' found")
    
        # 4. Verify High Priority heading exists
        if high_priority_idx is None:
            errors.append("[X] heading_2 'High Priority' not found")
        else:
            checks_passed.append("[C] heading_2 'High Priority' found")
    
        # 5. Verify Dashboard heading exists
        if dashboard_heading_idx is None:
            errors.append("[X] heading_2 '🎯 Feature Implementation Dashboard' not found")
        else:
            checks_passed.append("[C] heading_2 '🎯 Feature Implementation Dashboard' found")
    
        dashboard_block = page_blocks_sorted[dashboard_heading_idx]
    
        # 6. Verify Dashboard heading is AFTER intro paragraph but BEFORE High Priority
        if dashboard_heading_idx <= intro_paragraph_idx:
            errors.append(f"[X] '🎯 Feature Implementation Dashboard' must appear AFTER intro paragraph (Dashboard at idx {dashboard_heading_idx}, intro at {intro_paragraph_idx})")
        else:
            checks_passed.append(f"[C] '🎯 Feature Implementation Dashboard' must appear AFTER intro paragraph (Dashboard at idx {dashboard_heading_idx}, intro at {intro_paragraph_idx})")
    
        if dashboard_heading_idx >= high_priority_idx:
            errors.append(f"[X] '🎯 Feature Implementation Dashboard' must appear BEFORE 'High Priority' heading (Dashboard at idx {dashboard_heading_idx}, High Priority at {high_priority_idx})")
        else:
            checks_passed.append(f"[C] '🎯 Feature Implementation Dashboard' must appear BEFORE 'High Priority' heading (Dashboard at idx {dashboard_heading_idx}, High Priority at {high_priority_idx})")
    
        # 7. Find blue callout with 📊 icon after Dashboard heading
        blue_callout = None
        blue_callout_idx = None
        for idx in range(dashboard_heading_idx + 1, high_priority_idx):
            block = page_blocks_sorted[idx]
            if block.get("type") == "callout":
                props = block.get("properties", {})
                bg_color = props.get("backgroundColor", "").lower()
                icon = props.get("icon", "")
            
                if "blue" in bg_color and "📊" in icon:
                    blue_callout = block
                    blue_callout_idx = idx
                    break
    
        if not blue_callout:
            errors.append("[X] Blue callout with 📊 icon not found after Dashboard heading")
        else:
            checks_passed.append("[C] Blue callout with 📊 icon found after Dashboard heading")
    
        # 8. Verify callout contains 'Feature Pipeline Status'
        callout_content = blue_callout.get("content", "").lower()
        if "feature pipeline status" not in callout_content:
            errors.append(f"[X] Callout should contain 'Feature Pipeline Status'. Got: '{blue_callout.get('content', '')}'")
        else:
            checks_passed.append(f"[C] Callout should contain 'Feature Pipeline Status'. Got: '{blue_callout.get('content', '')}'")
    
        # 9. Find bulleted list items with statistics after callout but before High Priority
        bulleted_items = []
        for idx in range(blue_callout_idx + 1, high_priority_idx):
            block = page_blocks_sorted[idx]
            if block.get("type") == "bulletedList":
                bulleted_items.append(block)
    
        if len(bulleted_items) < 3:
            errors.append(f"[X] Expected at least 3 bulleted list items for statistics, found {len(bulleted_items)}")
        else:
            checks_passed.append(f"[C] Found at least 3 bulleted list items for statistics ({len(bulleted_items)})")
    
        # 10. Validate statistics in bulleted items
        found_total = False
        found_implemented = False
        found_pipeline = False
    
        for item in bulleted_items:
            content = item.get("content", "")
            content_lower = content.lower()
        
            # Check for Total Features Requested line
            if "total features requested" in content_lower:
                if "3" in content:
                    found_total = True
        
            # Check for Implemented line
            if "implemented" in content_lower:
                if "1" in content and "33" in content and "%" in content:
                    found_implemented = True
        
            # Check for In Pipeline line
            if "in pipeline" in content_lower or "pipeline" in content_lower:
                if "2" in content and "66" in content and "%" in content:
                    found_pipeline = True
    
        if not found_total:
            errors.append("[X] Missing bulleted item 'Total Features Requested: 3'")
        else:
            checks_passed.append("[C] has bulleted item 'Total Features Requested: 3'")
    
        if not found_implemented:
            errors.append("[X] Missing bulleted item 'Implemented: 1 (33.33%)'")
        else:
            checks_passed.append("[C] has bulleted item 'Implemented: 1 (33.33%)'")
    
        if not found_pipeline:
            errors.append("[X] Missing bulleted item 'In Pipeline: 2 (66.67%)'")
        else:
            checks_passed.append("[C] has bulleted item 'In Pipeline: 2 (66.67%)'")
    
        # 11. Verify Community Suggestions section exists
        if community_suggestions_idx is None:
            errors.append("[X] heading_2 'Community Suggestions' not found")
        else:
            checks_passed.append("[C] heading_2 'Community Suggestions' found")
    
        # 12. Verify 'Advanced search filters' bulleted item exists
        if advanced_search_idx is None:
            errors.append("[X] bulletedList 'Advanced search filters' not found")
        else:
            checks_passed.append("[C] bulletedList 'Advanced search filters' found")
    
        # 13. Verify Next Sprint Candidates heading exists
        if next_sprint_idx is None:
            errors.append("[X] heading_3 '🚀 Next Sprint Candidates' not found")
        else:
            checks_passed.append("[C] heading_3 '🚀 Next Sprint Candidates' found")
    
        next_sprint_block = page_blocks_sorted[next_sprint_idx]
    
        # 14. Verify Next Sprint Candidates is AFTER Advanced search filters
        if next_sprint_idx <= advanced_search_idx:
            errors.append(f"[X] '🚀 Next Sprint Candidates' must appear AFTER 'Advanced search filters' (Next Sprint at idx {next_sprint_idx}, Advanced search at {advanced_search_idx})")
        else:
            checks_passed.append(f"[C] '🚀 Next Sprint Candidates' must appear AFTER 'Advanced search filters' (Next Sprint at idx {next_sprint_idx}, Advanced search at {advanced_search_idx})")
    
        # 15. Find numbered list items after Next Sprint Candidates heading
        numbered_items = []
        for idx in range(next_sprint_idx + 1, len(page_blocks_sorted)):
            block = page_blocks_sorted[idx]
            if block.get("type") == "numberedList":
                numbered_items.append(block)
            elif block.get("type") in ["heading1", "heading2", "heading3"]:
                # Stop at next heading
                break
    
        if len(numbered_items) < 2:
            errors.append(f"[X] Expected at least 2 numbered list items for unchecked todos, found {len(numbered_items)}")
        else:
            checks_passed.append(f"[C] Found at least 2 numbered list items for unchecked todos ({len(numbered_items)})")
    
        # 16. Validate numbered list contains the unchecked todo items
        found_keyboard = False
        found_export = False
    
        for item in numbered_items:
            content = item.get("content", "").lower()
        
            if "keyboard shortcuts customization" in content:
                found_keyboard = True
            if "export to pdf functionality" in content or "export to pdf" in content:
                found_export = True
    
        if not found_keyboard:
            errors.append("[X] Missing numbered item 'Keyboard shortcuts customization'")
        else:
            checks_passed.append("[C] has numbered item 'Keyboard shortcuts customization'")
    
        if not found_export:
            errors.append("[X] Missing numbered item 'Export to PDF functionality'")
        else:
            checks_passed.append("[C] has numbered item 'Export to PDF functionality'")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

    # -----------------------------------------------------------------------------
    # Task: feature-requests-analysis
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_feature_requests_analysis(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Feature Analysis section on Feature Requests page.
    
    Goal: Navigate to Feature Requests page and add a Feature Analysis section
    after the Low Priority section with priority distribution statistics.
    
    Validation steps (ordered):
    1. Find the Feature Requests page
    2. Find heading_2 'Low Priority' section
    3. Verify heading_2 '🔍 Feature Analysis' exists AFTER Low Priority
    4. Verify purple callout with 📊 icon exists after the Feature Analysis heading
    5. Verify heading_3 'Request Distribution' exists (inside/after callout)
    6. Verify bulleted list with priority counts and percentages:
       - '🔴 High Priority: [X] requests ([Y]% of total)'
       - '🟡 Medium Priority: [Z] requests ([A]% of total)'
       - '🟢 Low Priority: [B] requests ([C]% of total)'
    7. Verify italic paragraph with date appears below the callout
    
    Weights: All-or-nothing (1.0 if all pass, 0.0 otherwise)
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    
    # 1. Find the Feature Requests page
    try:
        feature_page = _find_page_by_title(final_state_backend, "Feature Requests")
        if not feature_page:
            errors.append("[X] Feature Requests page not found")
        else:
            checks_passed.append("[C] Feature Requests page found")
    
        page_id = feature_page.get("_id")
        page_blocks = _get_blocks_for_page(final_state_backend, page_id)
    
        if not page_blocks:
            errors.append("[X] No blocks found on Feature Requests page")
        else:
            checks_passed.append("[C] blocks found on Feature Requests page")
    
        # Sort blocks by order
        page_blocks_sorted = sorted(page_blocks, key=lambda b: b.get("order", 0))
    
        # 2. Find key reference points
        low_priority_idx = None
        feature_analysis_idx = None
    
        # Also track all priority sections to count todos
        high_priority_idx = None
        medium_priority_idx = None
    
        for idx, block in enumerate(page_blocks_sorted):
            content = block.get("content", "")
            content_lower = content.lower()
            block_type = block.get("type", "")
        
            if block_type == "heading2":
                if "high priority" in content_lower:
                    high_priority_idx = idx
                elif "medium priority" in content_lower:
                    medium_priority_idx = idx
                elif "low priority" in content_lower:
                    low_priority_idx = idx
                elif "feature analysis" in content_lower:
                    feature_analysis_idx = idx
    
        # 3. Verify Low Priority section exists
        if low_priority_idx is None:
            errors.append("[X] heading_2 'Low Priority' not found on Feature Requests page")
        else:
            checks_passed.append("[C] heading_2 'Low Priority' found on Feature Requests page")
    
        # 4. Verify Feature Analysis heading exists AFTER Low Priority
        if feature_analysis_idx is None:
            errors.append("[X] heading_2 '🔍 Feature Analysis' not found")
        else:
            checks_passed.append("[C] heading_2 '🔍 Feature Analysis' found")
    
        feature_analysis_block = page_blocks_sorted[feature_analysis_idx]
        if feature_analysis_idx <= low_priority_idx:
            errors.append(f"[X] '🔍 Feature Analysis' must appear AFTER 'Low Priority' section (Feature Analysis at idx {feature_analysis_idx}, Low Priority at {low_priority_idx})")
        else:
            checks_passed.append(f"[C] '🔍 Feature Analysis' must appear AFTER 'Low Priority' section (Feature Analysis at idx {feature_analysis_idx}, Low Priority at {low_priority_idx})")
    
        # 5. Find purple callout with 📊 icon after Feature Analysis heading
        purple_callout = None
        purple_callout_idx = None
        for idx in range(feature_analysis_idx + 1, len(page_blocks_sorted)):
            block = page_blocks_sorted[idx]
            if block.get("type") == "callout":
                props = block.get("properties", {})
                bg_color = props.get("backgroundColor", "").lower()
                icon = props.get("icon", "")
            
                if "purple" in bg_color and "📊" in icon:
                    purple_callout = block
                    purple_callout_idx = idx
                    break
    
        if not purple_callout:
            errors.append("[X] Purple callout with 📊 icon not found after Feature Analysis heading")
        else:
            checks_passed.append("[C] Purple callout with 📊 icon found after Feature Analysis heading")
    
        # 6. Find heading_3 'Request Distribution' (after feature analysis heading, can be inside/after callout)
        request_distribution_heading = None
        request_distribution_idx = None
        for idx in range(feature_analysis_idx + 1, len(page_blocks_sorted)):
            block = page_blocks_sorted[idx]
            if block.get("type") == "heading3":
                content = block.get("content", "").lower()
                if "request distribution" in content:
                    request_distribution_heading = block
                    request_distribution_idx = idx
                    break
    
        if not request_distribution_heading:
            errors.append("[X] heading_3 'Request Distribution' not found after Feature Analysis section")
        else:
            checks_passed.append("[C] heading_3 'Request Distribution' found after Feature Analysis section")
    
        # 7. Count todos in each priority section for validation
        def count_todos_in_section(start_idx: int, end_idx: Optional[int]) -> int:
            """Count todo blocks between start_idx and end_idx."""
            count = 0
            end = end_idx if end_idx is not None else len(page_blocks_sorted)
            for i in range(start_idx + 1, end):
                block = page_blocks_sorted[i]
                # Stop if we hit another heading2
                if block.get("type") == "heading2":
                    break
                if block.get("type") == "todo":
                    count += 1
            return count
    
        # Determine section boundaries
        high_count = 0
        medium_count = 0
        low_count = 0
    
        if high_priority_idx is not None:
            # Find next heading after high priority
            next_after_high = medium_priority_idx if medium_priority_idx else low_priority_idx
            high_count = count_todos_in_section(high_priority_idx, next_after_high)
    
        if medium_priority_idx is not None:
            medium_count = count_todos_in_section(medium_priority_idx, low_priority_idx)
    
        if low_priority_idx is not None:
            low_count = count_todos_in_section(low_priority_idx, feature_analysis_idx)
    
        total_count = high_count + medium_count + low_count
    
        # 8. Find bulleted list items with priority distribution after Request Distribution heading
        bulleted_items = []
        for idx in range(request_distribution_idx + 1, len(page_blocks_sorted)):
            block = page_blocks_sorted[idx]
            if block.get("type") == "bulletedList":
                bulleted_items.append(block)
            elif block.get("type") in ["heading2", "heading3", "paragraph"]:
                # Stop when we hit another section or the final paragraph
                if block.get("type") == "paragraph":
                    # This might be the final date paragraph, so we allow it
                    pass
                else:
                    break
    
        if len(bulleted_items) < 3:
            errors.append(f"[X] Expected at least 3 bulleted list items for priority distribution, found {len(bulleted_items)}")
        else:
            checks_passed.append(f"[C] Found at least 3 bulleted list items for priority distribution ({len(bulleted_items)})")
    
        # 9. Validate bulleted list content contains priority counts
        found_high = False
        found_medium = False
        found_low = False
    
        for item in bulleted_items:
            content = item.get("content", "")
            content_lower = content.lower()
        
            # Check for High Priority line
            if "🔴" in content and "high priority" in content_lower:
                # Should contain count and percentage
                if "request" in content_lower and "%" in content:
                    found_high = True
        
            # Check for Medium Priority line  
            if "🟡" in content and "medium priority" in content_lower:
                if "request" in content_lower and "%" in content:
                    found_medium = True
        
            # Check for Low Priority line
            if "🟢" in content and "low priority" in content_lower:
                if "request" in content_lower and "%" in content:
                    found_low = True
    
        if not found_high:
            errors.append("[X] Missing bulleted item '🔴 High Priority: [X] requests ([Y]% of total)'")
        else:
            checks_passed.append("[C] has bulleted item '🔴 High Priority: [X] requests ([Y]% of total)'")
    
        if not found_medium:
            errors.append("[X] Missing bulleted item '🟡 Medium Priority: [Z] requests ([A]% of total)'")
        else:
            checks_passed.append("[C] has bulleted item '🟡 Medium Priority: [Z] requests ([A]% of total)'")
    
        if not found_low:
            errors.append("[X] Missing bulleted item '🟢 Low Priority: [B] requests ([C]% of total)'")
        else:
            checks_passed.append("[C] has bulleted item '🟢 Low Priority: [B] requests ([C]% of total)'")
    
        # 10. Find italic paragraph with date after the distribution section
        date_paragraph = None
        # Look for paragraph after callout (checking after bulleted items or after callout)
        search_start = purple_callout_idx + 1 if purple_callout_idx else feature_analysis_idx + 1
        for idx in range(search_start, len(page_blocks_sorted)):
            block = page_blocks_sorted[idx]
            if block.get("type") == "paragraph":
                content = block.get("content", "")
                content_lower = content.lower()
            
                # Check for date-related content
                if "last analysis" in content_lower or "performed on" in content_lower:
                    date_paragraph = block
                    break
    
        if not date_paragraph:
            errors.append("[X] Italic paragraph with '*Last analysis performed on [DATE]*' not found")
        else:
            checks_passed.append("[C] Italic paragraph with '*Last analysis performed on [DATE]*' found")
    
        # Check for italic formatting (either via properties or markdown asterisks)
        date_content = date_paragraph.get("content", "")
        date_props = date_paragraph.get("properties", {})
        has_italic = (
            date_props.get("italic") or 
            date_props.get("isItalic") or
            (date_content.startswith("*") and date_content.endswith("*"))
        )
    
        if not has_italic:
            errors.append(f"[X] Date paragraph should be in italic format. Got: '{date_content}'")
        else:
            checks_passed.append(f"[C] Date paragraph should be in italic format. Got: '{date_content}'")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

    # -----------------------------------------------------------------------------
    # Task: project-documentation-architecture
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_project_documentation_architecture(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate comprehensive documentation architecture on Project Documentation page.
    
    Goal: Navigate to 'Project Documentation' page and build a documentation architecture
    by analyzing all descendant pages and creating structured content.
    
    Page hierarchy:
    - Project Documentation (page-22)
      - Architecture (page-23) -> Frontend Architecture (page-24), Backend Architecture (page-27)
      - Deployment Guide (page-29) -> CI/CD Pipeline (page-30)
    
    Validation steps (ordered):
    1. Find the 'Project Documentation' page
    2. Verify heading_1 '📚 Project Documentation Hub' exists
    3. Verify paragraph 'Centralized repository for all project artifacts and technical documentation.'
    4. Verify heading_2 '📂 Documentation Categories' exists after intro
    5. For 'Architecture' child: verify heading_3 'Architecture Section' followed by callout (gray background)
       with 'Subdocuments: Frontend Architecture, Backend Architecture'
    6. For 'Deployment Guide' child: verify heading_3 'Deployment Guide Section' followed by callout (blue background)
       with 'Subdocuments: CI/CD Pipeline'
    7. Verify heading_2 '🔍 Quick Navigation' exists
    8. Verify 5 bookmark blocks exist (one for each page in hierarchy)
    9. Verify heading_2 '📊 Documentation Coverage' exists
    10. Verify code block (yaml) with 'total_pages: 5', 'top_level: 2', 'nested_pages: 3', 'max_depth: 2'
    
    Weights: All-or-nothing (1.0 if all pass, 0.0 otherwise)
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    
    # 1. Find the Project Documentation page
    try:
        project_doc_page = _find_page_by_title(final_state_backend, "Project Documentation")
        if not project_doc_page:
            errors.append("[X] Project Documentation page not found")
        else:
            checks_passed.append("[C] Project Documentation page found")
    
        page_id = project_doc_page.get("_id")
        page_blocks = _get_blocks_for_page(final_state_backend, page_id)
    
        if not page_blocks:
            errors.append("[X] No blocks found on Project Documentation page")
        else:
            checks_passed.append("[C] blocks found on Project Documentation page")
    
        # Sort blocks by order
        page_blocks_sorted = sorted(page_blocks, key=lambda b: b.get("order", 0))
    
        # 2. Verify heading_1 '📚 Project Documentation Hub'
        main_heading_found = False
        main_heading_idx = None
    
        for idx, block in enumerate(page_blocks_sorted):
            block_type = block.get("type", "")
            content = block.get("content", "")
        
            if block_type in ["heading1", "heading_1"]:
                if "📚" in content and "project documentation hub" in content.lower():
                    main_heading_found = True
                    main_heading_idx = idx
                    break
    
        if not main_heading_found:
            errors.append("[X] heading_1 '📚 Project Documentation Hub' not found")
        else:
            checks_passed.append("[C] heading_1 '📚 Project Documentation Hub' found")
    
        # 3. Verify intro paragraph
        intro_paragraph_found = False
        intro_idx = None
    
        for idx, block in enumerate(page_blocks_sorted[main_heading_idx + 1:], start=main_heading_idx + 1):
            block_type = block.get("type", "")
            content = block.get("content", "").lower()
        
            if block_type == "paragraph":
                if "centralized repository" in content and "technical documentation" in content:
                    intro_paragraph_found = True
                    intro_idx = idx
                    break
            # Stop if we hit a heading
            if block_type.startswith("heading"):
                break
    
        if not intro_paragraph_found:
            errors.append("[X] Intro paragraph 'Centralized repository for all project artifacts and technical documentation.' not found")
        else:
            checks_passed.append("[C] Intro paragraph 'Centralized repository for all project artifacts and technical documentation.' found")
    
        # 4. Verify heading_2 '📂 Documentation Categories'
        categories_heading_found = False
        categories_idx = None
    
        for idx, block in enumerate(page_blocks_sorted[intro_idx + 1:], start=intro_idx + 1):
            block_type = block.get("type", "")
            content = block.get("content", "")
        
            if block_type in ["heading2", "heading_2"]:
                if "📂" in content and "documentation categories" in content.lower():
                    categories_heading_found = True
                    categories_idx = idx
                    break
    
        if not categories_heading_found:
            errors.append("[X] heading_2 '📂 Documentation Categories' not found after intro paragraph")
        else:
            checks_passed.append("[C] heading_2 '📂 Documentation Categories' found after intro paragraph")
    
        # 5. Verify Architecture Section with gray callout
        architecture_section_found = False
        architecture_section_idx = None
        architecture_callout_found = False
    
        for idx, block in enumerate(page_blocks_sorted[categories_idx + 1:], start=categories_idx + 1):
            block_type = block.get("type", "")
            content = block.get("content", "")
        
            if block_type in ["heading3", "heading_3"]:
                if "architecture" in content.lower() and "section" in content.lower():
                    architecture_section_found = True
                    architecture_section_idx = idx
                    break
    
        if not architecture_section_found:
            errors.append("[X] heading_3 'Architecture Section' not found after Documentation Categories")
        else:
            checks_passed.append("[C] heading_3 'Architecture Section' found after Documentation Categories")
    
        # Check for gray callout after Architecture Section
        for idx, block in enumerate(page_blocks_sorted[architecture_section_idx + 1:], start=architecture_section_idx + 1):
            block_type = block.get("type", "")
            content = block.get("content", "").lower()
            props = block.get("properties", {})
        
            if block_type == "callout":
                bg_color = props.get("backgroundColor", "").lower()
                if bg_color in ["gray", "grey", "gray_background", "grey_background"]:
                    # Check content mentions subdocuments
                    if "subdocuments" in content:
                        # Verify it mentions Frontend Architecture and Backend Architecture
                        if "frontend architecture" in content and "backend architecture" in content:
                            architecture_callout_found = True
                            break
            # Stop if we hit another heading
            if block_type.startswith("heading"):
                break
    
        if not architecture_callout_found:
            errors.append("[X] Gray callout with 'Subdocuments: Frontend Architecture, Backend Architecture' not found after Architecture Section")
        else:
            checks_passed.append("[C] Gray callout with 'Subdocuments: Frontend Architecture, Backend Architecture' found after Architecture Section")
    
        # 6. Verify Deployment Guide Section with blue callout
        deployment_section_found = False
        deployment_section_idx = None
        deployment_callout_found = False
    
        for idx, block in enumerate(page_blocks_sorted[architecture_section_idx + 1:], start=architecture_section_idx + 1):
            block_type = block.get("type", "")
            content = block.get("content", "")
        
            if block_type in ["heading3", "heading_3"]:
                if "deployment" in content.lower() and "section" in content.lower():
                    deployment_section_found = True
                    deployment_section_idx = idx
                    break
    
        if not deployment_section_found:
            errors.append("[X] heading_3 'Deployment Guide Section' not found after Architecture Section")
        else:
            checks_passed.append("[C] heading_3 'Deployment Guide Section' found after Architecture Section")
    
        # Check for blue callout after Deployment Guide Section
        for idx, block in enumerate(page_blocks_sorted[deployment_section_idx + 1:], start=deployment_section_idx + 1):
            block_type = block.get("type", "")
            content = block.get("content", "").lower()
            props = block.get("properties", {})
        
            if block_type == "callout":
                bg_color = props.get("backgroundColor", "").lower()
                if bg_color in ["blue", "blue_background"]:
                    # Check content mentions subdocuments
                    if "subdocuments" in content:
                        # Verify it mentions CI/CD Pipeline
                        if "ci/cd pipeline" in content or "ci/cd" in content:
                            deployment_callout_found = True
                            break
            # Stop if we hit another heading
            if block_type.startswith("heading"):
                break
    
        if not deployment_callout_found:
            errors.append("[X] Blue callout with 'Subdocuments: CI/CD Pipeline' not found after Deployment Guide Section")
        else:
            checks_passed.append("[C] Blue callout with 'Subdocuments: CI/CD Pipeline' found after Deployment Guide Section")
    
        # 7. Verify heading_2 '🔍 Quick Navigation'
        quick_nav_found = False
        quick_nav_idx = None
    
        for idx, block in enumerate(page_blocks_sorted[deployment_section_idx + 1:], start=deployment_section_idx + 1):
            block_type = block.get("type", "")
            content = block.get("content", "")
        
            if block_type in ["heading2", "heading_2"]:
                if "🔍" in content and "quick navigation" in content.lower():
                    quick_nav_found = True
                    quick_nav_idx = idx
                    break
    
        if not quick_nav_found:
            errors.append("[X] heading_2 '🔍 Quick Navigation' not found")
        else:
            checks_passed.append("[C] heading_2 '🔍 Quick Navigation' found")
    
        # 8. Verify 5 bookmark blocks exist for all pages in hierarchy
        # Expected pages: Architecture, Frontend Architecture, Backend Architecture, Deployment Guide, CI/CD Pipeline
        expected_pages = [
            ("architecture", "🏗️"),
            ("frontend architecture", "🎨"),
            ("backend architecture", "⚙️"),
            ("deployment guide", "🚀"),
            ("ci/cd pipeline", "🔄"),
        ]
    
        bookmark_blocks = []
        for idx, block in enumerate(page_blocks_sorted[quick_nav_idx + 1:], start=quick_nav_idx + 1):
            block_type = block.get("type", "")
        
            if block_type == "bookmark":
                bookmark_blocks.append(block)
            # Stop if we hit heading_2 '📊 Documentation Coverage'
            if block_type in ["heading2", "heading_2"]:
                content = block.get("content", "").lower()
                if "documentation coverage" in content:
                    break
    
        if len(bookmark_blocks) < 5:
            errors.append(f"[X] Expected 5 bookmark blocks for all pages in hierarchy, found {len(bookmark_blocks)}")
        else:
            checks_passed.append(f"[C] Found 5 bookmark blocks for all pages in hierarchy as expected")
    
        # Verify each expected page has a bookmark
        for page_title, icon in expected_pages:
            found = False
            for bookmark in bookmark_blocks:
                content = bookmark.get("content", "").lower()
                props = bookmark.get("properties", {})
                caption = props.get("caption", "").lower() if props.get("caption") else ""
                url = props.get("url", "").lower() if props.get("url") else ""
            
                # Check if bookmark mentions the page (in content, caption, or url)
                if page_title in content or page_title in caption or page_title.replace(" ", "-") in url:
                    found = True
                    break
        
            if not found:
                errors.append(f"[X] Bookmark for '{page_title}' not found in Quick Navigation section")
            else:
                checks_passed.append(f"[C] Bookmark for '{page_title}' found in Quick Navigation section")
    
        # 9. Verify heading_2 '📊 Documentation Coverage'
        coverage_heading_found = False
        coverage_idx = None
    
        for idx, block in enumerate(page_blocks_sorted[quick_nav_idx + 1:], start=quick_nav_idx + 1):
            block_type = block.get("type", "")
            content = block.get("content", "")
        
            if block_type in ["heading2", "heading_2"]:
                if "📊" in content and "documentation coverage" in content.lower():
                    coverage_heading_found = True
                    coverage_idx = idx
                    break
    
        if not coverage_heading_found:
            errors.append("[X] heading_2 '📊 Documentation Coverage' not found")
        else:
            checks_passed.append("[C] heading_2 '📊 Documentation Coverage' found")
    
        # 10. Verify code block (yaml) with correct counts
        code_block_found = False
    
        for idx, block in enumerate(page_blocks_sorted[coverage_idx + 1:], start=coverage_idx + 1):
            block_type = block.get("type", "")
            content = block.get("content", "").lower()
            props = block.get("properties", {})
        
            if block_type == "code":
                language = props.get("language", "").lower()
            
                if language == "yaml" or "yaml" in language:
                    # Verify content has the required counts
                    has_total = "total_pages" in content and "5" in content
                    has_top = "top_level" in content and "2" in content
                    has_nested = "nested_pages" in content and "3" in content
                    has_depth = "max_depth" in content and "2" in content
                
                    if has_total and has_top and has_nested and has_depth:
                        code_block_found = True
                        break
                    else:
                        missing = []
                        if not has_total:
                            missing.append("total_pages: 5")
                        if not has_top:
                            missing.append("top_level: 2")
                        if not has_nested:
                            missing.append("nested_pages: 3")
                        if not has_depth:
                            missing.append("max_depth: 2")
                        errors.append(f"[X] YAML code block missing or incorrect values: {', '.join(missing)}")
    
        if not code_block_found:
            errors.append("[X] Code block (yaml) with documentation coverage stats not found after '📊 Documentation Coverage' heading")
        else:
            checks_passed.append("[C] Code block (yaml) with documentation coverage stats found after '📊 Documentation Coverage' heading")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

    # -----------------------------------------------------------------------------
    # Task: company-handbook-employee-resources
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_company_handbook_employee_resources(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate employee resources section added to Company Handbook page.
    
    Goal: Navigate to the 'Company Handbook' page and add a new employee resources 
    section at the very end of all existing content.
    
    The Company Handbook page (page-16) initially has blocks up to order 15.
    The new content must appear after all existing content.
    
    Validation steps (ordered):
    1. Find the 'Company Handbook' page
    2. Get all blocks and sort by order
    3. Verify a divider block exists after the original content (order > 15)
    4. Verify heading_1 '🎯 Quick Reference Guide' exists after divider
    5. Verify green callout with '🌟' icon and text containing 'Essential resources for all team members'
    6. Verify heading_2 '📞 Important Contacts' exists
    7. Verify 3 numbered list items with IT Support, HR Department, and Facilities contacts
    8. Verify heading_2 '🔗 Useful Links' exists
    9. Verify 3 bookmark blocks with correct URLs and captions:
       - https://acme.corp/benefits with caption 'Employee Benefits Portal'
       - https://acme.corp/timeoff with caption 'Time Off Request System'
       - https://acme.corp/training with caption 'Learning Management System'
    10. Verify quote block with 'Your success is our success - Acme Corp'
    
    Weights: All-or-nothing (1.0 if all pass, 0.0 otherwise)
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    
    # 1. Find the Company Handbook page
    try:
        handbook_page = _find_page_by_title(final_state_backend, "Company Handbook")
        if not handbook_page:
            errors.append("[X] Company Handbook page not found")
        else:
            checks_passed.append("[C] Company Handbook page found")
    
        page_id = handbook_page.get("_id")
        page_blocks = _get_blocks_for_page(final_state_backend, page_id)
    
        if not page_blocks:
            errors.append("[X] No blocks found on Company Handbook page")
        else:
            checks_passed.append("[C] blocks found on Company Handbook page")
    
        # Sort blocks by order
        page_blocks_sorted = sorted(page_blocks, key=lambda b: b.get("order", 0))
    
        # The original content has blocks with order 0-15 (16 blocks total)
        # New content should appear after order 15
    
        # 2. Find divider block after original content
        divider_found = False
        divider_idx = None
        for idx, block in enumerate(page_blocks_sorted):
            if block.get("type") == "divider" and block.get("order", 0) > 15:
                divider_found = True
                divider_idx = idx
                break
    
        if not divider_found:
            errors.append("[X] Divider block not found after original content (must be after order 15)")
        else:
            checks_passed.append("[C] Divider block found after original content (must be after order 15)")
    
        # 3. Find heading_1 '🎯 Quick Reference Guide' after divider
        quick_ref_heading = None
        quick_ref_idx = None
        for idx in range(divider_idx + 1, len(page_blocks_sorted)):
            block = page_blocks_sorted[idx]
            if block.get("type") == "heading1":
                content = block.get("content", "")
                if "🎯" in content and "quick reference guide" in content.lower():
                    quick_ref_heading = block
                    quick_ref_idx = idx
                    break
    
        if not quick_ref_heading:
            errors.append("[X] heading_1 '🎯 Quick Reference Guide' not found after divider")
        else:
            checks_passed.append("[C] heading_1 '🎯 Quick Reference Guide' found after divider")
    
        # 4. Find green callout with 🌟 icon after heading
        green_callout = None
        green_callout_idx = None
        for idx in range(quick_ref_idx + 1, len(page_blocks_sorted)):
            block = page_blocks_sorted[idx]
            if block.get("type") == "callout":
                props = block.get("properties", {})
                bg_color = props.get("backgroundColor", "").lower()
                icon = props.get("icon", "")
                content = block.get("content", "").lower()
            
                if "green" in bg_color and "🌟" in icon:
                    if "essential resources" in content and "team members" in content:
                        green_callout = block
                        green_callout_idx = idx
                        break
    
        if not green_callout:
            errors.append("[X] Green callout with '🌟' icon and 'Essential resources for all team members' text not found")
        else:
            checks_passed.append("[C] Green callout with '🌟' icon and 'Essential resources for all team members' text found")
    
        # 5. Find heading_2 '📞 Important Contacts'
        contacts_heading = None
        contacts_heading_idx = None
        for idx in range(green_callout_idx + 1, len(page_blocks_sorted)):
            block = page_blocks_sorted[idx]
            if block.get("type") == "heading2":
                content = block.get("content", "")
                if "📞" in content and "important contacts" in content.lower():
                    contacts_heading = block
                    contacts_heading_idx = idx
                    break
    
        if not contacts_heading:
            errors.append("[X] heading_2 '📞 Important Contacts' not found after callout")
        else:
            checks_passed.append("[C] heading_2 '📞 Important Contacts' found after callout")
    
        # 6. Find 3 numbered list items with contacts
        numbered_items = []
        for idx in range(contacts_heading_idx + 1, len(page_blocks_sorted)):
            block = page_blocks_sorted[idx]
            if block.get("type") == "numberedList":
                numbered_items.append(block)
            elif block.get("type") in ["heading2", "heading1"]:
                # Stop at next heading
                break
    
        if len(numbered_items) < 3:
            errors.append(f"[X] Expected 3 numbered list items for contacts, found {len(numbered_items)}")
        else:
            checks_passed.append(f"[C] Found 3 numbered list items for contacts as expected")
    
        # Validate contact content
        it_support_found = False
        hr_found = False
        facilities_found = False
    
        for item in numbered_items:
            content = item.get("content", "").lower()
            if "it support" in content and "it@acme.corp" in content and "1234" in content:
                it_support_found = True
            if "hr department" in content and "hr@acme.corp" in content and "5678" in content:
                hr_found = True
            if "facilities" in content and "facilities@acme.corp" in content and "9012" in content:
                facilities_found = True
    
        if not it_support_found:
            errors.append("[X] Numbered list item for IT Support (it@acme.corp, ext. 1234) not found")
        else:
            checks_passed.append("[C] Numbered list item for IT Support (it@acme.corp, ext. 1234) found")
        if not hr_found:
            errors.append("[X] Numbered list item for HR Department (hr@acme.corp, ext. 5678) not found")
        else:
            checks_passed.append("[C] Numbered list item for HR Department (hr@acme.corp, ext. 5678) found")
        if not facilities_found:
            errors.append("[X] Numbered list item for Facilities (facilities@acme.corp, ext. 9012) not found")
        else:
            checks_passed.append("[C] Numbered list item for Facilities (facilities@acme.corp, ext. 9012) found")
    
        # 7. Find heading_2 '🔗 Useful Links'
        links_heading = None
        links_heading_idx = None
        for idx in range(contacts_heading_idx + 1, len(page_blocks_sorted)):
            block = page_blocks_sorted[idx]
            if block.get("type") == "heading2":
                content = block.get("content", "")
                if "🔗" in content and "useful links" in content.lower():
                    links_heading = block
                    links_heading_idx = idx
                    break
    
        if not links_heading:
            errors.append("[X] heading_2 '🔗 Useful Links' not found")
        else:
            checks_passed.append("[C] heading_2 '🔗 Useful Links' found")
    
        # 8. Find 3 bookmark blocks with correct URLs and captions
        bookmarks = []
        for idx in range(links_heading_idx + 1, len(page_blocks_sorted)):
            block = page_blocks_sorted[idx]
            if block.get("type") == "bookmark":
                bookmarks.append(block)
            elif block.get("type") in ["heading2", "heading1", "quote"]:
                # Stop at next section or quote
                break
    
        if len(bookmarks) < 3:
            errors.append(f"[X] Expected 3 bookmark blocks, found {len(bookmarks)}")
        else:
            checks_passed.append(f"[C] Found 3 bookmark blocks as expected")
    
        # Validate bookmarks
        benefits_found = False
        timeoff_found = False
        training_found = False
    
        for bm in bookmarks:
            props = bm.get("properties", {})
            url = props.get("url", "").lower()
            caption = props.get("caption", "").lower()
            content = bm.get("content", "").lower()  # Some implementations store URL in content
        
            # Check URL in both properties.url and content
            url_check = url if url else content
        
            if "acme.corp/benefits" in url_check:
                if "employee benefits portal" in caption or "employee benefits portal" in content:
                    benefits_found = True
            if "acme.corp/timeoff" in url_check:
                if "time off request system" in caption or "time off request system" in content:
                    timeoff_found = True
            if "acme.corp/training" in url_check:
                if "learning management system" in caption or "learning management system" in content:
                    training_found = True
    
        if not benefits_found:
            errors.append("[X] Bookmark to 'https://acme.corp/benefits' with caption 'Employee Benefits Portal' not found")
        else:
            checks_passed.append("[C] Bookmark to 'https://acme.corp/benefits' with caption 'Employee Benefits Portal' found")
        if not timeoff_found:
            errors.append("[X] Bookmark to 'https://acme.corp/timeoff' with caption 'Time Off Request System' not found")
        else:
            checks_passed.append("[C] Bookmark to 'https://acme.corp/timeoff' with caption 'Time Off Request System' found")
        if not training_found:
            errors.append("[X] Bookmark to 'https://acme.corp/training' with caption 'Learning Management System' not found")
        else:
            checks_passed.append("[C] Bookmark to 'https://acme.corp/training' with caption 'Learning Management System' found")
    
        # 9. Find quote block with company quote
        quote_found = False
        for idx in range(links_heading_idx + 1, len(page_blocks_sorted)):
            block = page_blocks_sorted[idx]
            if block.get("type") == "quote":
                content = block.get("content", "").lower()
                if "your success is our success" in content and "acme corp" in content:
                    quote_found = True
                    break
    
        if not quote_found:
            errors.append("[X] Quote block 'Your success is our success - Acme Corp' not found")
        else:
            checks_passed.append("[C] Quote block 'Your success is our success - Acme Corp' found")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

    # -----------------------------------------------------------------------------
    # Task: engineering-wiki-tool-versions
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_engineering_wiki_tool_versions(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Tool Versions section insertion on Engineering Wiki page.
    
    Goal: Navigate to Engineering Wiki page and add a '🔧 Tool Versions' section
    after the 'Development Setup' section content, with a callout, code block, 
    paragraph, and divider.
    
    Validation steps (ordered):
    1. Find the 'Engineering Wiki' page (page-4)
    2. Get all blocks sorted by order
    3. Find 'Development Setup' heading_2 and its last content block (order 9)
    4. Find 'Environment Variables' heading_2 (order 10) as the next section marker
    5. Verify heading_2 '🔧 Tool Versions' appears AFTER 'Development Setup' content 
       and BEFORE 'Environment Variables'
    6. Verify callout with orange_background and ⚠️ icon with exact text
    7. Verify code block with 'json' language and exact JSON content
    8. Verify paragraph with 'For installation instructions, refer to the Development Setup section above.'
    9. Verify divider block follows the paragraph
    10. Verify correct ordering: heading -> callout -> code -> paragraph -> divider
    
    Weights: All-or-nothing (1.0 if all pass, 0.0 otherwise)
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    
    # 1. Find the Engineering Wiki page
    try:
        wiki_page = _find_page_by_title(final_state_backend, "Engineering Wiki")
        if not wiki_page:
            errors.append("[X] Engineering Wiki page not found")
        else:
            checks_passed.append("[C] Engineering Wiki page found")
    
        page_id = wiki_page.get("_id")
        page_blocks = _get_blocks_for_page(final_state_backend, page_id)
    
        if not page_blocks:
            errors.append("[X] No blocks found on Engineering Wiki page")
        else:
            checks_passed.append("[C] blocks found on Engineering Wiki page")
    
        # Sort blocks by order
        page_blocks_sorted = sorted(page_blocks, key=lambda b: b.get("order", 0))
    
        # 2. Find key reference points
        dev_setup_idx = None
        dev_setup_last_content_idx = None
        env_vars_idx = None
        tool_versions_idx = None
    
        for idx, block in enumerate(page_blocks_sorted):
            content = block.get("content", "")
            content_lower = content.lower()
            block_type = block.get("type", "")
        
            # Find "Development Setup" heading_2
            if block_type in ["heading2", "heading_2"]:
                if "development setup" in content_lower:
                    dev_setup_idx = idx
                elif "environment variables" in content_lower:
                    env_vars_idx = idx
                elif "🔧" in content and "tool versions" in content_lower:
                    tool_versions_idx = idx
    
        if dev_setup_idx is None:
            errors.append("[X] heading_2 'Development Setup' not found on Engineering Wiki page")
        else:
            checks_passed.append("[C] heading_2 'Development Setup' found on Engineering Wiki page")
    
        if env_vars_idx is None:
            errors.append("[X] heading_2 'Environment Variables' not found on Engineering Wiki page")
        else:
            checks_passed.append("[C] heading_2 'Environment Variables' found on Engineering Wiki page")
    
        # 3. Find the last content block under Development Setup section
        # The Development Setup section has numbered list items, find the last one before another heading
        for idx in range(dev_setup_idx + 1, env_vars_idx):
            block = page_blocks_sorted[idx]
            block_type = block.get("type", "")
            # Track numbered lists (the Development Setup content)
            if block_type in ["numberedList", "numbered_list", "numberedListItem", "numbered_list_item"]:
                dev_setup_last_content_idx = idx
    
        if dev_setup_last_content_idx is None:
            # Fallback: just use the index right after the heading
            dev_setup_last_content_idx = dev_setup_idx
    
        # 4. Verify heading_2 '🔧 Tool Versions' exists after Development Setup content
        if tool_versions_idx is None:
            errors.append("[X] heading_2 '🔧 Tool Versions' not found on Engineering Wiki page")
        else:
            checks_passed.append("[C] heading_2 '🔧 Tool Versions' found on Engineering Wiki page")
    
        tool_versions_order = page_blocks_sorted[tool_versions_idx].get("order", 0)
        dev_setup_last_order = page_blocks_sorted[dev_setup_last_content_idx].get("order", 0)
        env_vars_order = page_blocks_sorted[env_vars_idx].get("order", 0)
    
        if not (dev_setup_last_order < tool_versions_order < env_vars_order):
            errors.append(f"[X] heading_2 🔧 Tool Versions should appear after Development Setup content  (order {dev_setup_last_order}) and before Environment Variables (order {env_vars_order}),  but found at order {tool_versions_order}")
        else:
            checks_passed.append(f"[C] heading_2 🔧 Tool Versions should appear after Development Setup content (order {dev_setup_last_order}) and before Environment Variables (order {env_vars_order}), but found at order {tool_versions_order}")
    
        # 5. Find blocks in the Tool Versions section (between tool_versions_idx and env_vars_idx)
        section_blocks = []
        for idx in range(tool_versions_idx + 1, len(page_blocks_sorted)):
            block = page_blocks_sorted[idx]
            block_order = block.get("order", 0)
            # Stop when we reach Environment Variables section
            if block_order >= env_vars_order:
                break
            section_blocks.append(block)
    
        if not section_blocks:
            errors.append("[X] No blocks found in '🔧 Tool Versions' section")
        else:
            checks_passed.append("[C] blocks found in '🔧 Tool Versions' section")
    
        # 6. Verify callout with orange_background and ⚠️ icon
        callout_block = None
        callout_idx = None
        for idx, block in enumerate(section_blocks):
            if block.get("type") == "callout":
                callout_block = block
                callout_idx = idx
                break
    
        if not callout_block:
            errors.append("[X] Callout block not found in '🔧 Tool Versions' section")
        else:
            checks_passed.append("[C] Callout block found in '🔧 Tool Versions' section")
    
        callout_props = callout_block.get("properties", {})
        callout_bg = callout_props.get("backgroundColor", "")
        callout_icon = callout_props.get("icon", "")
        callout_content = callout_block.get("content", "")
    
        if callout_bg != "orange_background":
            errors.append(f"[X] Callout should have 'orange_background', found '{callout_bg}'")
        else:
            checks_passed.append(f"[C] Callout should have 'orange_background', found '{callout_bg}'")
    
        if "⚠️" not in callout_icon:
            errors.append(f"[X] Callout should have '⚠️' icon, found '{callout_icon}'")
        else:
            checks_passed.append(f"[C] Callout should have '⚠️' icon, found '{callout_icon}'")
    
        expected_callout_text = "Ensure all team members use these exact versions for consistency"
        if expected_callout_text not in callout_content:
            errors.append(f"[X] Callout should contain '{expected_callout_text}', found '{callout_content}'")
        else:
            checks_passed.append(f"[C] Callout should contain '{expected_callout_text}', found '{callout_content}'")
    
        # 7. Verify code block with 'json' language and exact content
        code_block = None
        code_idx = None
        for idx, block in enumerate(section_blocks):
            if block.get("type") == "code":
                code_block = block
                code_idx = idx
                break
    
        if not code_block:
            errors.append("[X] Code block not found in '🔧 Tool Versions' section")
        else:
            checks_passed.append("[C] Code block found in '🔧 Tool Versions' section")
    
        code_props = code_block.get("properties", {})
        code_language = code_props.get("language", "").lower()
    
        if code_language != "json":
            errors.append(f"[X] Code block should have language 'json', found '{code_language}'")
        else:
            checks_passed.append(f"[C] Code block should have language 'json', found '{code_language}'")
    
        code_content = code_block.get("content", "")
    
        # Verify JSON content contains all required key-value pairs
        required_versions = {
            '"node"': '"18.17.0"',
            '"npm"': '"9.6.7"',
            '"docker"': '"24.0.5"',
            '"postgres"': '"15.3"'
        }
    
        for key, value in required_versions.items():
            if key not in code_content:
                errors.append(f"[X] Code block missing key {key}")
            else:
                checks_passed.append(f"[C] Code block has key {key}")
            if value not in code_content:
                errors.append(f"[X] Code block missing value {value} for key {key}")
            else:
                checks_passed.append(f"[C] Code block has value {value} for key {key}")
    
        # 8. Verify paragraph with installation reference
        paragraph_block = None
        paragraph_idx = None
        for idx, block in enumerate(section_blocks):
            if block.get("type") == "paragraph":
                content = block.get("content", "")
                if "installation instructions" in content.lower() and "development setup" in content.lower():
                    paragraph_block = block
                    paragraph_idx = idx
                    break
    
        if not paragraph_block:
            errors.append("[X] Paragraph with 'For installation instructions, refer to the Development Setup section above.' not found")
        else:
            checks_passed.append("[C] Paragraph with 'For installation instructions, refer to the Development Setup section above.' found")
    
        expected_para_text = "For installation instructions, refer to the Development Setup section above."
        para_content = paragraph_block.get("content", "")
        if expected_para_text not in para_content:
            errors.append(f"[X] Paragraph should contain '{expected_para_text}', found '{para_content}'")
        else:
            checks_passed.append(f"[C] Paragraph should contain '{expected_para_text}', found '{para_content}'")
    
        # 9. Verify divider block exists
        divider_block = None
        divider_idx = None
        for idx, block in enumerate(section_blocks):
            if block.get("type") == "divider":
                divider_block = block
                divider_idx = idx
                break
    
        if not divider_block:
            errors.append("[X] Divider block not found in '🔧 Tool Versions' section")
        else:
            checks_passed.append("[C] Divider block found in '🔧 Tool Versions' section")
    
        # 10. Verify correct ordering: callout -> code -> paragraph -> divider
        if callout_idx is None or code_idx is None or paragraph_idx is None or divider_idx is None:
            errors.append("[X] Not all required blocks found in correct positions")
        else:
            checks_passed.append("[C] all required blocks found in correct positions")
    
        # Check callout comes before code
        callout_order = callout_block.get("order", 0)
        code_order = code_block.get("order", 0)
        para_order = paragraph_block.get("order", 0)
        divider_order = divider_block.get("order", 0)
    
        if not (callout_order < code_order):
            errors.append(f"[X] Callout (order {callout_order}) should appear before code block (order {code_order})")
        else:
            checks_passed.append(f"[C] Callout (order {callout_order}) should appear before code block (order {code_order})")
    
        if not (code_order < para_order):
            errors.append(f"[X] Code block (order {code_order}) should appear before paragraph (order {para_order})")
        else:
            checks_passed.append(f"[C] Code block (order {code_order}) should appear before paragraph (order {para_order})")
    
        if not (para_order < divider_order):
            errors.append(f"[X] Paragraph (order {para_order}) should appear before divider (order {divider_order})")
        else:
            checks_passed.append(f"[C] Paragraph (order {para_order}) should appear before divider (order {divider_order})")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

    # -----------------------------------------------------------------------------
    # Task: japan-travel-planner-v2
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_japan_travel_planner(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Japan Travel Planner page creation with comprehensive 3-day itinerary.
    
    Goal: Create a new page titled '🌏 Japan Travel Planner' as a top-level page in 
    workspace-1 with a structured 3-day Tokyo itinerary.
    
    Validation steps (ordered):
    1. Verify page '🌏 Japan Travel Planner' exists as top-level page (no parentId)
    2. Verify heading1 '🌏 Japan Travel Planner' exists
    3. Verify heading2 '📍 Tokyo Adventure (3 Days)' exists
    4. Verify callout with yellow_background, '✈️' icon, and exact trip details text
    5. Verify heading2 '📅 Daily Itinerary' exists
    6. Verify heading3 '🌅 Day 1 - Traditional Tokyo' with 4 unchecked todos
    7. Verify heading3 '🏙️ Day 2 - Modern Tokyo' with 4 unchecked todos
    8. Verify heading3 '🗾 Day 3 - Day Trip' with 4 unchecked todos
    9. Verify heading2 '📝 Travel Notes' exists
    10. Verify paragraph with JR Pass and pocket WiFi reminder text
    
    Weights: All-or-nothing (1.0 if all pass, 0.0 otherwise)
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    
    # 1. Find the Japan Travel Planner page (check for exact title with emoji)
    try:
        travel_page = _find_page_by_title(final_state_backend, "🌏 Japan Travel Planner")
        if not travel_page:
            # Try without emoji
            travel_page = _find_page_by_title(final_state_backend, "Japan Travel Planner")
            if not travel_page:
                errors.append("[X] '🌏 Japan Travel Planner' page not found")
            else:
                checks_passed.append("[C] '🌏 Japan Travel Planner' page found")
    
        # Verify it's a top-level page (no parentId or parentId is None/empty)
        parent_id = travel_page.get("parentId")
        if parent_id:
            errors.append(f"[X] Japan Travel Planner should be a top-level page but has parentId: {parent_id}")
        else:
            checks_passed.append(f"[C] Japan Travel Planner should be a top-level page but has parentId: {parent_id}")
    
        page_id = travel_page.get("_id")
        page_blocks = _get_blocks_for_page(final_state_backend, page_id)
    
        if not page_blocks:
            errors.append("[X] No blocks found on Japan Travel Planner page")
        else:
            checks_passed.append("[C] blocks found on Japan Travel Planner page")
    
        # Sort blocks by order
        page_blocks_sorted = sorted(page_blocks, key=lambda b: b.get("order", 0))
    
        block_idx = 0
    
        # 2. Check heading1: '🌏 Japan Travel Planner'
        if block_idx >= len(page_blocks_sorted):
            errors.append("[X] Missing heading1 block")
        else:
            checks_passed.append("[C] has heading1 block")
        block = page_blocks_sorted[block_idx]
        if block.get("type") != "heading1":
            errors.append(f"[X] First block should be heading1, got {block.get('type')}")
        else:
            checks_passed.append(f"[C] First block should be heading1, got {block.get('type')}")
        h1_content = block.get("content", "")
        if "japan travel planner" not in h1_content.lower():
            errors.append(f"[X] heading1 should contain 'Japan Travel Planner', got '{h1_content}'")
        else:
            checks_passed.append(f"[C] heading1 should contain 'Japan Travel Planner', got '{h1_content}'")
        block_idx += 1
    
        # 3. Check heading2: '📍 Tokyo Adventure (3 Days)'
        if block_idx >= len(page_blocks_sorted):
            errors.append("[X] Missing heading2 '📍 Tokyo Adventure (3 Days)'")
        else:
            checks_passed.append("[C] has heading2 '📍 Tokyo Adventure (3 Days)'")
        block = page_blocks_sorted[block_idx]
        if block.get("type") != "heading2":
            errors.append(f"[X] Block {block_idx} should be heading2, got {block.get('type')}")
        else:
            checks_passed.append(f"[C] Block {block_idx} should be heading2, got {block.get('type')}")
        h2_content = block.get("content", "").lower()
        if "tokyo adventure" not in h2_content or "3 days" not in h2_content:
            errors.append(f"[X] heading2 should contain 'Tokyo Adventure' and '3 Days', got '{block.get('content')}'")
        else:
            checks_passed.append(f"[C] heading2 should contain 'Tokyo Adventure' and '3 Days', got '{block.get('content')}'")
        block_idx += 1
    
        # 4. Check callout with yellow_background, '✈️' icon, trip details
        if block_idx >= len(page_blocks_sorted):
            errors.append("[X] Missing callout block")
        else:
            checks_passed.append("[C] has callout block")
        callout_block = page_blocks_sorted[block_idx]
        if callout_block.get("type") != "callout":
            errors.append(f"[X] Block {block_idx} should be callout, got {callout_block.get('type')}")
        else:
            checks_passed.append(f"[C] Block {block_idx} should be callout, got {callout_block.get('type')}")
    
        callout_props = callout_block.get("properties", {})
        bg_color = callout_props.get("backgroundColor", "")
        if "yellow" not in bg_color.lower():
            errors.append(f"[X] Callout should have yellow background, got {bg_color}")
        else:
            checks_passed.append(f"[C] Callout should have yellow background, got {bg_color}")
    
        callout_icon = callout_props.get("icon", "")
        if "✈️" not in callout_icon and "✈" not in callout_icon:
            errors.append(f"[X] Callout should have '✈️' icon, got {callout_icon}")
        else:
            checks_passed.append(f"[C] Callout should have '✈️' icon, got {callout_icon}")
    
        callout_content = callout_block.get("content", "").lower()
        if "trip duration" not in callout_content:
            errors.append(f"[X] Callout should contain 'Trip Duration', got '{callout_block.get('content')}'")
        else:
            checks_passed.append(f"[C] Callout should contain 'Trip Duration', got '{callout_block.get('content')}'")
        if "january 15-17" not in callout_content and "january 15" not in callout_content:
            errors.append(f"[X] Callout should contain 'January 15-17, 2024', got '{callout_block.get('content')}'")
        else:
            checks_passed.append(f"[C] Callout should contain 'January 15-17, 2024', got '{callout_block.get('content')}'")
        if "150,000" not in callout_content and "150000" not in callout_content:
            errors.append(f"[X] Callout should contain '¥150,000', got '{callout_block.get('content')}'")
        else:
            checks_passed.append(f"[C] Callout should contain '¥150,000', got '{callout_block.get('content')}'")
        block_idx += 1
    
        # 5. Check heading2: '📅 Daily Itinerary'
        if block_idx >= len(page_blocks_sorted):
            errors.append("[X] Missing heading2 '📅 Daily Itinerary'")
        else:
            checks_passed.append("[C] has heading2 '📅 Daily Itinerary'")
        block = page_blocks_sorted[block_idx]
        if block.get("type") != "heading2":
            errors.append(f"[X] Block {block_idx} should be heading2, got {block.get('type')}")
        else:
            checks_passed.append(f"[C] Block {block_idx} should be heading2, got {block.get('type')}")
        if "daily itinerary" not in block.get("content", "").lower():
            errors.append(f"[X] heading2 should contain 'Daily Itinerary', got '{block.get('content')}'")
        else:
            checks_passed.append(f"[C] heading2 should contain 'Daily Itinerary', got '{block.get('content')}'")
        block_idx += 1
    
        # 6. Check heading3 '🌅 Day 1 - Traditional Tokyo' + 4 todos
        if block_idx >= len(page_blocks_sorted):
            errors.append("[X] Missing heading3 'Day 1 - Traditional Tokyo'")
        else:
            checks_passed.append("[C] has heading3 'Day 1 - Traditional Tokyo'")
        block = page_blocks_sorted[block_idx]
        if block.get("type") != "heading3":
            errors.append(f"[X] Block {block_idx} should be heading3 for Day 1, got {block.get('type')}")
        else:
            checks_passed.append(f"[C] Block {block_idx} should be heading3 for Day 1, got {block.get('type')}")
        day1_content = block.get("content", "").lower()
        if "day 1" not in day1_content or "traditional tokyo" not in day1_content:
            errors.append(f"[X] heading3 should contain 'Day 1' and 'Traditional Tokyo', got '{block.get('content')}'")
        else:
            checks_passed.append(f"[C] heading3 should contain 'Day 1' and 'Traditional Tokyo', got '{block.get('content')}'")
        block_idx += 1
    
        # Day 1 todos
        day1_todos = [
            "senso-ji temple",
            "nakamise shopping street",
            "tsukiji outer market",
            "tokyo national museum"
        ]
    
        for i, expected_todo in enumerate(day1_todos):
            if block_idx >= len(page_blocks_sorted):
                errors.append(f"[X] Missing Day 1 todo #{i+1}: {expected_todo}")
            else:
                checks_passed.append(f"[C] has Day 1 todo #{i+1}: {expected_todo}")
            todo_block = page_blocks_sorted[block_idx]
            if todo_block.get("type") != "todo":
                errors.append(f"[X] Block {block_idx} should be todo for Day 1, got {todo_block.get('type')}")
            else:
                checks_passed.append(f"[C] Block {block_idx} should be todo for Day 1, got {todo_block.get('type')}")
            todo_content = todo_block.get("content", "").lower()
            if expected_todo not in todo_content:
                errors.append(f"[X] Day 1 todo #{i+1} should contain '{expected_todo}', got '{todo_block.get('content')}'")
            else:
                checks_passed.append(f"[C] Day 1 todo #{i+1} should contain '{expected_todo}', got '{todo_block.get('content')}'")
            # Verify unchecked
            checked = todo_block.get("properties", {}).get("checked", False)
            if checked:
                errors.append(f"[X] Day 1 todo #{i+1} should be unchecked")
            else:
                checks_passed.append(f"[C] Day 1 todo #{i+1} should be unchecked")
            block_idx += 1
    
        # 7. Check heading3 '🏙️ Day 2 - Modern Tokyo' + 4 todos
        if block_idx >= len(page_blocks_sorted):
            errors.append("[X] Missing heading3 'Day 2 - Modern Tokyo'")
        else:
            checks_passed.append("[C] has heading3 'Day 2 - Modern Tokyo'")
        block = page_blocks_sorted[block_idx]
        if block.get("type") != "heading3":
            errors.append(f"[X] Block {block_idx} should be heading3 for Day 2, got {block.get('type')}")
        else:
            checks_passed.append(f"[C] Block {block_idx} should be heading3 for Day 2, got {block.get('type')}")
        day2_content = block.get("content", "").lower()
        if "day 2" not in day2_content or "modern tokyo" not in day2_content:
            errors.append(f"[X] heading3 should contain 'Day 2' and 'Modern Tokyo', got '{block.get('content')}'")
        else:
            checks_passed.append(f"[C] heading3 should contain 'Day 2' and 'Modern Tokyo', got '{block.get('content')}'")
        block_idx += 1
    
        # Day 2 todos
        day2_todos = [
            "teamlab borderless",
            "shibuya crossing",
            "harajuku",
            "roppongi"
        ]
    
        for i, expected_todo in enumerate(day2_todos):
            if block_idx >= len(page_blocks_sorted):
                errors.append(f"[X] Missing Day 2 todo #{i+1}: {expected_todo}")
            else:
                checks_passed.append(f"[C] has Day 2 todo #{i+1}: {expected_todo}")
            todo_block = page_blocks_sorted[block_idx]
            if todo_block.get("type") != "todo":
                errors.append(f"[X] Block {block_idx} should be todo for Day 2, got {todo_block.get('type')}")
            else:
                checks_passed.append(f"[C] Block {block_idx} should be todo for Day 2, got {todo_block.get('type')}")
            todo_content = todo_block.get("content", "").lower()
            if expected_todo not in todo_content:
                errors.append(f"[X] Day 2 todo #{i+1} should contain '{expected_todo}', got '{todo_block.get('content')}'")
            else:
                checks_passed.append(f"[C] Day 2 todo #{i+1} should contain '{expected_todo}', got '{todo_block.get('content')}'")
            # Verify unchecked
            checked = todo_block.get("properties", {}).get("checked", False)
            if checked:
                errors.append(f"[X] Day 2 todo #{i+1} should be unchecked")
            else:
                checks_passed.append(f"[C] Day 2 todo #{i+1} should be unchecked")
            block_idx += 1
    
        # 8. Check heading3 '🗾 Day 3 - Day Trip' + 4 todos
        if block_idx >= len(page_blocks_sorted):
            errors.append("[X] Missing heading3 'Day 3 - Day Trip'")
        else:
            checks_passed.append("[C] has heading3 'Day 3 - Day Trip'")
        block = page_blocks_sorted[block_idx]
        if block.get("type") != "heading3":
            errors.append(f"[X] Block {block_idx} should be heading3 for Day 3, got {block.get('type')}")
        else:
            checks_passed.append(f"[C] Block {block_idx} should be heading3 for Day 3, got {block.get('type')}")
        day3_content = block.get("content", "").lower()
        if "day 3" not in day3_content or "day trip" not in day3_content:
            errors.append(f"[X] heading3 should contain 'Day 3' and 'Day Trip', got '{block.get('content')}'")
        else:
            checks_passed.append(f"[C] heading3 should contain 'Day 3' and 'Day Trip', got '{block.get('content')}'")
        block_idx += 1
    
        # Day 3 todos
        day3_todos = [
            "kamakura",
            "great buddha",
            "hokoku-ji bamboo",
            "return to tokyo"
        ]
    
        for i, expected_todo in enumerate(day3_todos):
            if block_idx >= len(page_blocks_sorted):
                errors.append(f"[X] Missing Day 3 todo #{i+1}: {expected_todo}")
            else:
                checks_passed.append(f"[C] has Day 3 todo #{i+1}: {expected_todo}")
            todo_block = page_blocks_sorted[block_idx]
            if todo_block.get("type") != "todo":
                errors.append(f"[X] Block {block_idx} should be todo for Day 3, got {todo_block.get('type')}")
            else:
                checks_passed.append(f"[C] Block {block_idx} should be todo for Day 3, got {todo_block.get('type')}")
            todo_content = todo_block.get("content", "").lower()
            if expected_todo not in todo_content:
                errors.append(f"[X] Day 3 todo #{i+1} should contain '{expected_todo}', got '{todo_block.get('content')}'")
            else:
                checks_passed.append(f"[C] Day 3 todo #{i+1} should contain '{expected_todo}', got '{todo_block.get('content')}'")
            # Verify unchecked
            checked = todo_block.get("properties", {}).get("checked", False)
            if checked:
                errors.append(f"[X] Day 3 todo #{i+1} should be unchecked")
            else:
                checks_passed.append(f"[C] Day 3 todo #{i+1} should be unchecked")
            block_idx += 1
    
        # 9. Check heading2 '📝 Travel Notes'
        if block_idx >= len(page_blocks_sorted):
            errors.append("[X] Missing heading2 '📝 Travel Notes'")
        else:
            checks_passed.append("[C] has heading2 '📝 Travel Notes'")
        block = page_blocks_sorted[block_idx]
        if block.get("type") != "heading2":
            errors.append(f"[X] Block {block_idx} should be heading2 for Travel Notes, got {block.get('type')}")
        else:
            checks_passed.append(f"[C] Block {block_idx} should be heading2 for Travel Notes, got {block.get('type')}")
        if "travel notes" not in block.get("content", "").lower():
            errors.append(f"[X] heading2 should contain 'Travel Notes', got '{block.get('content')}'")
        else:
            checks_passed.append(f"[C] heading2 should contain 'Travel Notes', got '{block.get('content')}'")
        block_idx += 1
    
        # 10. Check paragraph with JR Pass and pocket WiFi reminder
        if block_idx >= len(page_blocks_sorted):
            errors.append("[X] Missing Travel Notes paragraph")
        else:
            checks_passed.append("[C] has Travel Notes paragraph")
        para_block = page_blocks_sorted[block_idx]
        if para_block.get("type") != "paragraph":
            errors.append(f"[X] Block {block_idx} should be paragraph, got {para_block.get('type')}")
        else:
            checks_passed.append(f"[C] Block {block_idx} should be paragraph, got {para_block.get('type')}")
    
        para_content = para_block.get("content", "").lower()
        if "jr pass" not in para_content:
            errors.append(f"[X] Travel Notes paragraph should contain 'JR Pass', got '{para_block.get('content')}'")
        else:
            checks_passed.append(f"[C] Travel Notes paragraph should contain 'JR Pass', got '{para_block.get('content')}'")
        if "pocket wifi" not in para_content and "wifi" not in para_content:
            errors.append(f"[X] Travel Notes paragraph should contain 'pocket WiFi', got '{para_block.get('content')}'")
        else:
            checks_passed.append(f"[C] Travel Notes paragraph should contain 'pocket WiFi', got '{para_block.get('content')}'")
        if "google translate" not in para_content:
            errors.append(f"[X] Travel Notes paragraph should contain 'Google Translate', got '{para_block.get('content')}'")
        else:
            checks_passed.append(f"[C] Travel Notes paragraph should contain 'Google Translate', got '{para_block.get('content')}'")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

    # -----------------------------------------------------------------------------
    # Task: team-directory-org-chart
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_team_directory_org_chart(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate team structure visualization on Team Directory page.
    
    Goal: On the 'Team Directory' page, implement an organizational chart visualization
    with mermaid diagram and append email addresses to each person's bullet point.
    
    Current Team Directory structure (page-8):
    - block-8-1: heading1 "Team Directory" (order 0)
    - block-8-2: paragraph intro (order 1)
    - block-8-3: heading2 "Engineering Team" (order 2)
    - block-8-4: bulletedList "Alice Chen - Tech Lead" (order 3)
    - block-8-5: bulletedList "Bob Martinez - Senior Engineer" (order 4)
    - block-8-6: bulletedList "Frank Zhang - Backend Engineer" (order 5)
    - block-8-7: heading2 "Design Team" (order 6)
    - block-8-8: bulletedList "Carol Williams - Design Lead" (order 7)
    - block-8-9: image "Team Photo" (order 8)
    
    Validation steps (ordered):
    1. Find the 'Team Directory' page
    2. Find 'Design Team' heading2 and the image block
    3. Verify heading2 '🏢 Organizational Chart' exists AFTER 'Design Team' but BEFORE image
    4. Verify mermaid code block exists after Org Chart heading with correct syntax
    5. Verify callout with cyan_background exists after the code block
    6. Verify each person's bullet has email appended in format ' - firstname.lastname@company.com'
    
    Weights: All-or-nothing (1.0 if all pass, 0.0 otherwise)
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    
    # 1. Find the Team Directory page
    try:
        team_directory_page = _find_page_by_title(final_state_backend, "Team Directory")
        if not team_directory_page:
            errors.append("[X] Team Directory page not found")
        else:
            checks_passed.append("[C] Team Directory page found")
    
        page_id = team_directory_page.get("_id")
        page_blocks = _get_blocks_for_page(final_state_backend, page_id)
    
        if not page_blocks:
            errors.append("[X] No blocks found on Team Directory page")
        else:
            checks_passed.append("[C] blocks found on Team Directory page")
    
        # Sort blocks by order
        page_blocks_sorted = sorted(page_blocks, key=lambda b: b.get("order", 0))
    
        # 2. Find key reference points
        design_team_idx = None
        image_block_idx = None
        org_chart_idx = None
    
        for idx, block in enumerate(page_blocks_sorted):
            content = block.get("content", "")
            content_lower = content.lower()
            block_type = block.get("type", "")
        
            if block_type == "heading2":
                if "design team" in content_lower:
                    design_team_idx = idx
                elif "organizational chart" in content_lower or "🏢" in content:
                    org_chart_idx = idx
            elif block_type == "image":
                # Find the team photo image
                if "team" in content_lower or image_block_idx is None:
                    image_block_idx = idx
    
        # 3. Verify Design Team heading exists
        if design_team_idx is None:
            errors.append("[X] heading_2 'Design Team' not found on Team Directory page")
        else:
            checks_passed.append("[C] heading_2 'Design Team' found on Team Directory page")
    
        # Verify image block exists
        if image_block_idx is None:
            errors.append("[X] Image block not found on Team Directory page")
        else:
            checks_passed.append("[C] Image block found on Team Directory page")
    
        # 4. Verify '🏢 Organizational Chart' heading exists AFTER Design Team but BEFORE image
        if org_chart_idx is None:
            errors.append("[X] heading_2 '🏢 Organizational Chart' not found")
        else:
            checks_passed.append("[C] heading_2 '🏢 Organizational Chart' found")
    
        org_chart_block = page_blocks_sorted[org_chart_idx]
        if org_chart_idx <= design_team_idx:
            errors.append(f"[X] '🏢 Organizational Chart' must appear AFTER 'Design Team' section (Org Chart at idx {org_chart_idx}, Design Team at {design_team_idx})")
        else:
            checks_passed.append(f"[C] '🏢 Organizational Chart' must appear AFTER 'Design Team' section (Org Chart at idx {org_chart_idx}, Design Team at {design_team_idx})")
    
        if org_chart_idx >= image_block_idx:
            errors.append(f"[X] '🏢 Organizational Chart' must appear BEFORE the image block (Org Chart at idx {org_chart_idx}, Image at {image_block_idx})")
        else:
            checks_passed.append(f"[C] '🏢 Organizational Chart' must appear BEFORE the image block (Org Chart at idx {org_chart_idx}, Image at {image_block_idx})")
    
        # 5. Find mermaid code block after Org Chart heading
        mermaid_code_block = None
        mermaid_code_idx = None
        for idx in range(org_chart_idx + 1, len(page_blocks_sorted)):
            block = page_blocks_sorted[idx]
            if block.get("type") == "code":
                props = block.get("properties", {})
                language = props.get("language", "").lower()
                if language == "mermaid":
                    mermaid_code_block = block
                    mermaid_code_idx = idx
                    break
            # Stop if we hit the image block
            if block.get("type") == "image":
                break
    
        if not mermaid_code_block:
            errors.append("[X] Mermaid code block not found after Organizational Chart heading")
        else:
            checks_passed.append("[C] Mermaid code block found after Organizational Chart heading")
    
        # Verify mermaid content has required elements
        mermaid_content = mermaid_code_block.get("content", "")
        required_elements = [
            "graph TD",
            "Alice Chen - Tech Lead",
            "Bob Martinez",
            "Frank Zhang",
            "Carol Williams - Design Lead",
            "-->",
        ]
    
        for element in required_elements:
            if element not in mermaid_content:
                errors.append(f"[X] Mermaid code block missing required element: '{element}'")
            else:
                checks_passed.append(f"[C] Mermaid code block has required element: '{element}'")
    
        # 6. Find callout with cyan_background after the code block (but before image)
        cyan_callout = None
        for idx in range(mermaid_code_idx + 1, len(page_blocks_sorted)):
            block = page_blocks_sorted[idx]
            if block.get("type") == "callout":
                props = block.get("properties", {})
                bg_color = props.get("backgroundColor", "").lower()
                if "cyan" in bg_color:
                    cyan_callout = block
                    break
            # Stop if we hit the image block
            if block.get("type") == "image":
                break
    
        if not cyan_callout:
            errors.append("[X] Callout with cyan_background not found after mermaid code block")
        else:
            checks_passed.append("[C] Callout with cyan_background found after mermaid code block")
    
        # Verify callout content mentions reporting relationships
        callout_content = cyan_callout.get("content", "").lower()
        if "reporting" not in callout_content or "relationship" not in callout_content:
            errors.append(f"[X] Callout should mention 'reporting relationships'. Found: '{cyan_callout.get('content', '')}'")
        else:
            checks_passed.append(f"[C] Callout should mention 'reporting relationships'. Found: '{cyan_callout.get('content', '')}'")
    
        # 7. Verify each person's bullet has email appended
        # Expected format: "Name - Role - firstname.lastname@company.com"
        email_checks = [
            ("Alice Chen", "alice.chen@company.com"),
            ("Bob Martinez", "bob.martinez@company.com"),
            ("Frank Zhang", "frank.zhang@company.com"),
            ("Carol Williams", "carol.williams@company.com"),
        ]
    
        for name, expected_email in email_checks:
            found_bullet_with_email = False
            for block in page_blocks_sorted:
                if block.get("type") == "bulletedList":
                    content = block.get("content", "")
                    if name in content and expected_email in content:
                        found_bullet_with_email = True
                        break
        
            if not found_bullet_with_email:
                errors.append(f"[X] Bullet for '{name}' should have email '{expected_email}' appended")
            else:
                checks_passed.append(f"[C] Bullet for '{name}' should have email '{expected_email}' appended")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

    # -----------------------------------------------------------------------------
    # Task: sprint-retrospective-analysis-2
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_sprint_retrospective_analysis_2(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Sprint Retrospective Analysis section on Sprint Planning - Jan 15 page.
    
    Goal: Navigate to Sprint Planning - Jan 15 page and add a retrospective analysis
    section AFTER the Action Items section with completion statistics.
    
    Validation steps (ordered):
    1. Find the Sprint Planning - Jan 15 page
    2. Find heading_2 'Action Items' section
    3. Find all todos under Action Items to verify completion rate calculation
    4. Verify divider exists AFTER Action Items section (after todos)
    5. Verify heading_2 '📊 Sprint Retrospective Analysis' exists after divider
    6. Verify callout with orange_background and '📈' icon containing "100%" (2/2 checked)
    7. Verify heading_3 '✅ Completed Actions' exists
    8. Verify bulleted list with Alice's and Bob's completed tasks
    9. Verify heading_3 '⏳ Pending Actions' exists
    10. Verify quote block with Mark Twain quote
    11. Verify paragraph with italic text containing 'Last analysis update'
    
    Weights: All-or-nothing (1.0 if all pass, 0.0 otherwise)
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    
    # 1. Find the Sprint Planning - Jan 15 page
    try:
        sprint_page = _find_page_by_title(final_state_backend, "Sprint Planning - Jan 15")
        if not sprint_page:
            errors.append("[X] Sprint Planning - Jan 15 page not found")
        else:
            checks_passed.append("[C] Sprint Planning - Jan 15 page found")
    
        page_id = sprint_page.get("_id")
        page_blocks = _get_blocks_for_page(final_state_backend, page_id)
    
        if not page_blocks:
            errors.append("[X] No blocks found on Sprint Planning - Jan 15 page")
        else:
            checks_passed.append("[C] blocks found on Sprint Planning - Jan 15 page")
    
        # Sort blocks by order
        page_blocks_sorted = sorted(page_blocks, key=lambda b: b.get("order", 0))
    
        # 2. Find Action Items heading
        action_items_idx = None
        for idx, block in enumerate(page_blocks_sorted):
            content = block.get("content", "")
            content_lower = content.lower()
            block_type = block.get("type", "")
        
            if block_type == "heading2" and "action items" in content_lower:
                action_items_idx = idx
                break
    
        if action_items_idx is None:
            errors.append("[X] heading_2 'Action Items' not found on Sprint Planning - Jan 15 page")
        else:
            checks_passed.append("[C] heading_2 'Action Items' found on Sprint Planning - Jan 15 page")
    
        # 3. Find all todos after Action Items section and calculate completion
        checked_todos = []
        unchecked_todos = []
        last_todo_idx = action_items_idx
    
        for idx in range(action_items_idx + 1, len(page_blocks_sorted)):
            block = page_blocks_sorted[idx]
            block_type = block.get("type", "")
        
            # Stop if we hit a divider or another heading (non-todo section starts)
            if block_type in ["divider", "heading2"]:
                break
        
            if block_type == "todo":
                last_todo_idx = idx
                props = block.get("properties", {})
                content = block.get("content", "")
                if props.get("checked", False):
                    checked_todos.append(content)
                else:
                    unchecked_todos.append(content)
    
        total_todos = len(checked_todos) + len(unchecked_todos)
        if total_todos == 0:
            errors.append("[X] No todo items found under Action Items section")
        else:
            checks_passed.append("[C] todo items found under Action Items section")
    
        completion_rate = int((len(checked_todos) / total_todos) * 100)
    
        # 4. Find divider AFTER the todos
        divider_idx = None
        for idx in range(last_todo_idx + 1, len(page_blocks_sorted)):
            block = page_blocks_sorted[idx]
            if block.get("type") == "divider":
                divider_idx = idx
                break
    
        if divider_idx is None:
            errors.append("[X] Divider not found after Action Items section")
        else:
            checks_passed.append("[C] Divider found after Action Items section")
    
        # 5. Find heading_2 '📊 Sprint Retrospective Analysis' after divider
        retrospective_heading_idx = None
        for idx in range(divider_idx + 1, len(page_blocks_sorted)):
            block = page_blocks_sorted[idx]
            content = block.get("content", "")
            content_lower = content.lower()
            block_type = block.get("type", "")
        
            if block_type == "heading2" and "sprint retrospective analysis" in content_lower:
                if "📊" in content:
                    retrospective_heading_idx = idx
                    break
    
        if retrospective_heading_idx is None:
            errors.append("[X] heading_2 '📊 Sprint Retrospective Analysis' not found after divider")
        else:
            checks_passed.append("[C] heading_2 '📊 Sprint Retrospective Analysis' found after divider")
    
        # 6. Find callout with orange_background and 📈 icon containing completion rate
        orange_callout = None
        orange_callout_idx = None
        for idx in range(retrospective_heading_idx + 1, len(page_blocks_sorted)):
            block = page_blocks_sorted[idx]
            if block.get("type") == "callout":
                props = block.get("properties", {})
                bg_color = props.get("backgroundColor", "").lower()
                icon = props.get("icon", "")
                content = block.get("content", "")
            
                if "orange" in bg_color and "📈" in icon:
                    orange_callout = block
                    orange_callout_idx = idx
                    break
    
        if not orange_callout:
            errors.append("[X] Orange callout with 📈 icon not found after Sprint Retrospective Analysis heading")
        else:
            checks_passed.append("[C] Orange callout with 📈 icon found after Sprint Retrospective Analysis heading")
    
        # Verify completion rate is mentioned in callout
        callout_content = orange_callout.get("content", "").lower()
        if "completion rate" not in callout_content:
            errors.append(f"[X] Callout should mention 'completion rate'. Got: '{orange_callout.get('content', '')}'")
        else:
            checks_passed.append(f"[C] Callout should mention 'completion rate'. Got: '{orange_callout.get('content', '')}'")
    
        if f"{completion_rate}%" not in orange_callout.get("content", ""):
            errors.append(f"[X] Callout should contain '{completion_rate}%' (based on {len(checked_todos)}/{total_todos} checked). Got: '{orange_callout.get('content', '')}'")
        else:
            checks_passed.append(f"[C] Callout should contain '{completion_rate}%' (based on {len(checked_todos)}/{total_todos} checked). Got: '{orange_callout.get('content', '')}'")
    
        # 7. Find heading_3 '✅ Completed Actions'
        completed_heading_idx = None
        for idx in range(orange_callout_idx + 1, len(page_blocks_sorted)):
            block = page_blocks_sorted[idx]
            content = block.get("content", "")
            content_lower = content.lower()
            block_type = block.get("type", "")
        
            if block_type == "heading3" and "completed actions" in content_lower:
                if "✅" in content:
                    completed_heading_idx = idx
                    break
    
        if completed_heading_idx is None:
            errors.append("[X] heading_3 '✅ Completed Actions' not found after callout")
        else:
            checks_passed.append("[C] heading_3 '✅ Completed Actions' found after callout")
    
        # 8. Find bulleted list items with completed tasks
        completed_bullets = []
        for idx in range(completed_heading_idx + 1, len(page_blocks_sorted)):
            block = page_blocks_sorted[idx]
            block_type = block.get("type", "")
        
            if block_type == "bulletedList":
                completed_bullets.append(block.get("content", ""))
            elif block_type in ["heading3", "heading2"]:
                break
    
        # Verify we have bullet items for completed todos
        if len(checked_todos) > 0 and len(completed_bullets) == 0:
            errors.append(f"[X] Expected bulleted list items for {len(checked_todos)} completed actions, found none")
        else:
            checks_passed.append(f"[C] Expected bulleted list items for {len(checked_todos)} completed actions, found none")
    
        # Check that Alice and Bob tasks are mentioned (case-insensitive)
        alice_found = False
        bob_found = False
        for bullet in completed_bullets:
            bullet_lower = bullet.lower()
            if "alice" in bullet_lower:
                alice_found = True
            if "bob" in bullet_lower:
                bob_found = True
    
        if len(checked_todos) >= 1 and not alice_found:
            errors.append("[X] Completed Actions should list Alice's task")
        else:
            checks_passed.append("[C] Completed Actions should list Alice's task")
    
        if len(checked_todos) >= 2 and not bob_found:
            errors.append("[X] Completed Actions should list Bob's task")
        else:
            checks_passed.append("[C] Completed Actions should list Bob's task")
    
        # 9. Find heading_3 '⏳ Pending Actions'
        pending_heading_idx = None
        for idx in range(completed_heading_idx + 1, len(page_blocks_sorted)):
            block = page_blocks_sorted[idx]
            content = block.get("content", "")
            content_lower = content.lower()
            block_type = block.get("type", "")
        
            if block_type == "heading3" and "pending actions" in content_lower:
                if "⏳" in content:
                    pending_heading_idx = idx
                    break
    
        if pending_heading_idx is None:
            errors.append("[X] heading_3 '⏳ Pending Actions' not found")
        else:
            checks_passed.append("[C] heading_3 '⏳ Pending Actions' found")
    
        # 10. Find quote block with Mark Twain quote
        mark_twain_quote = None
        for idx in range(pending_heading_idx + 1, len(page_blocks_sorted)):
            block = page_blocks_sorted[idx]
            if block.get("type") == "quote":
                content = block.get("content", "")
                content_lower = content.lower()
                if "getting ahead" in content_lower and "getting started" in content_lower and "mark twain" in content_lower:
                    mark_twain_quote = block
                    break
    
        if not mark_twain_quote:
            errors.append("[X] Quote block with 'The secret of getting ahead is getting started. - Mark Twain' not found")
        else:
            checks_passed.append("[C] Quote block with 'The secret of getting ahead is getting started. - Mark Twain' found")
    
        # 11. Find italic paragraph with 'Last analysis update'
        date_paragraph = None
        for idx in range(pending_heading_idx + 1, len(page_blocks_sorted)):
            block = page_blocks_sorted[idx]
            if block.get("type") == "paragraph":
                content = block.get("content", "")
                content_lower = content.lower()
            
                if "last analysis update" in content_lower:
                    date_paragraph = block
                    break
    
        if not date_paragraph:
            errors.append("[X] Paragraph with 'Last analysis update' not found")
        else:
            checks_passed.append("[C] Paragraph with 'Last analysis update' found")
    
        # Check for italic formatting (either via properties or markdown underscores/asterisks)
        date_content = date_paragraph.get("content", "")
        date_props = date_paragraph.get("properties", {})
        has_italic = (
            date_props.get("italic") or 
            date_props.get("isItalic") or
            (date_content.startswith("_") and date_content.endswith("_")) or
            (date_content.startswith("*") and date_content.endswith("*"))
        )
    
        if not has_italic:
            errors.append(f"[X] Date paragraph should be in italic format (surrounded by _ or *). Got: '{date_content}'")
        else:
            checks_passed.append(f"[C] Date paragraph should be in italic format (surrounded by _ or *). Got: '{date_content}'")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

    # -----------------------------------------------------------------------------
    # Task: q1-q2-goals-comparison
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_q1_q2_goals_comparison(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Q1-Q2 Goals Comparison page creation.
    
    Goal: Create a new page '🎯 Q1-Q2 Goals Comparison' as a sibling of 'Project Roadmap',
    with quarterly goals analysis comparing Q1 and Q2 completion rates.
    
    Validation steps (ordered):
    1. Find the 'Project Roadmap' page to determine the sibling level
    2. Verify '🎯 Q1-Q2 Goals Comparison' page exists as sibling of Project Roadmap
    3. Get Q1 Goals and Q2 Goals pages, count todo blocks
    4. Verify heading1 '🎯 Quarterly Goals Analysis'
    5. Verify heading2 '📊 Completion Overview'
    6. Verify paragraph with Q1/Q2 stats: 'Q1: [X] goals ([Y] completed, [Z]% completion) | Q2: [A] goals ([B] completed, [C]% completion)'
    7. Verify heading2 '✅ Q1 Achievements'
    8. Verify bulleted list of all checked todos from Q1
    9. Verify heading2 '🎯 Q2 Targets'
    10. Verify numbered list of all todos from Q2 (checked and unchecked)
    11. Verify callout with blue_background, 📈 icon, text about completion rate improvement/decline
    
    Weights: All-or-nothing (1.0 if all pass, 0.0 otherwise)
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    
    # 1. Find Project Roadmap page to determine sibling level
    try:
        project_roadmap = _find_page_by_title(final_state_backend, "Project Roadmap")
        if not project_roadmap:
            errors.append("[X] Project Roadmap page not found")
        else:
            checks_passed.append("[C] Project Roadmap page found")
    
        roadmap_parent_id = project_roadmap.get("parentId")
    
        # 2. Find '🎯 Q1-Q2 Goals Comparison' page and verify it's a sibling of Project Roadmap
        comparison_page = _find_page_by_title(final_state_backend, "🎯 Q1-Q2 Goals Comparison")
        if not comparison_page:
            # Try without emoji
            comparison_page = _find_page_by_title(final_state_backend, "Q1-Q2 Goals Comparison")
            if not comparison_page:
                errors.append("[X] '🎯 Q1-Q2 Goals Comparison' page not found")
            else:
                checks_passed.append("[C] '🎯 Q1-Q2 Goals Comparison' page found")
    
        comparison_parent_id = comparison_page.get("parentId")
    
        # Verify they are siblings (same parentId)
        if comparison_parent_id != roadmap_parent_id:
            errors.append(f"[X] '🎯 Q1-Q2 Goals Comparison' is not a sibling of 'Project Roadmap' (different parentIds: {comparison_parent_id} vs {roadmap_parent_id})")
        else:
            checks_passed.append(f"[C] '🎯 Q1-Q2 Goals Comparison' is a sibling of 'Project Roadmap' (different parentIds: {comparison_parent_id} vs {roadmap_parent_id})")
    
        # 3. Get Q1 Goals and Q2 Goals pages to count todos
        q1_goals = _find_page_by_title_pattern_and_parent(final_state_backend, "Q1 Goals", project_roadmap.get("_id"))
        q2_goals = _find_page_by_title_pattern_and_parent(final_state_backend, "Q2 Goals", project_roadmap.get("_id"))
    
        if not q1_goals:
            errors.append("[X] Q1 Goals page not found as child of Project Roadmap")
        else:
            checks_passed.append("[C] Q1 Goals page found as child of Project Roadmap")
        if not q2_goals:
            errors.append("[X] Q2 Goals page not found as child of Project Roadmap")
        else:
            checks_passed.append("[C] Q2 Goals page found as child of Project Roadmap")
    
        # Count todos in Q1 and Q2
        q1_blocks = _get_blocks_for_page(final_state_backend, q1_goals.get("_id"))
        q2_blocks = _get_blocks_for_page(final_state_backend, q2_goals.get("_id"))
    
        q1_todos = [b for b in q1_blocks if b.get("type") == "todo"]
        q2_todos = [b for b in q2_blocks if b.get("type") == "todo"]
    
        q1_checked = [b for b in q1_todos if b.get("properties", {}).get("checked")]
        q2_checked = [b for b in q2_todos if b.get("properties", {}).get("checked")]
    
        q1_total = len(q1_todos)
        q2_total = len(q2_todos)
        q1_completed = len(q1_checked)
        q2_completed = len(q2_checked)
    
        # Calculate percentages
        q1_percentage = round((q1_completed / q1_total * 100) if q1_total > 0 else 0)
        q2_percentage = round((q2_completed / q2_total * 100) if q2_total > 0 else 0)
    
        # Determine if improved or declined
        if q2_percentage > q1_percentage:
            trend = "improved"
            diff = q2_percentage - q1_percentage
        else:
            trend = "declined"
            diff = q1_percentage - q2_percentage
    
        # 4. Get blocks from the comparison page and validate structure
        comparison_blocks = _get_blocks_for_page(final_state_backend, comparison_page.get("_id"))
    
        if len(comparison_blocks) < 8:
            errors.append(f"[X] '🎯 Q1-Q2 Goals Comparison' page has too few blocks ({len(comparison_blocks)})")
        else:
            checks_passed.append(f"[C] '🎯 Q1-Q2 Goals Comparison' page has too few blocks ({len(comparison_blocks)})")
    
        # Sort blocks by order
        comparison_blocks_sorted = sorted(comparison_blocks, key=lambda b: b.get("order", 0))
    
        block_idx = 0
    
        # 4. Verify heading1 '🎯 Quarterly Goals Analysis'
        if block_idx >= len(comparison_blocks_sorted):
            errors.append("[X] Missing heading1 block")
        else:
            checks_passed.append("[C] has heading1 block")
    
        h1_block = comparison_blocks_sorted[block_idx]
        if h1_block.get("type") != "heading1":
            errors.append(f"[X] First block should be heading1, got {h1_block.get('type')}")
        else:
            checks_passed.append(f"[C] First block should be heading1, got {h1_block.get('type')}")
    
        h1_content = h1_block.get("content", "").lower()
        if "quarterly goals analysis" not in h1_content:
            errors.append(f"[X] heading1 should contain 'Quarterly Goals Analysis', got '{h1_block.get('content')}'")
        else:
            checks_passed.append(f"[C] heading1 should contain 'Quarterly Goals Analysis', got '{h1_block.get('content')}'")
        block_idx += 1
    
        # 5. Verify heading2 '📊 Completion Overview'
        if block_idx >= len(comparison_blocks_sorted):
            errors.append("[X] Missing heading2 'Completion Overview' block")
        else:
            checks_passed.append("[C] has heading2 'Completion Overview' block")
    
        h2_overview = comparison_blocks_sorted[block_idx]
        if h2_overview.get("type") != "heading2":
            errors.append(f"[X] Block {block_idx} should be heading2 for Completion Overview, got {h2_overview.get('type')}")
        else:
            checks_passed.append(f"[C] Block {block_idx} should be heading2 for Completion Overview, got {h2_overview.get('type')}")
    
        h2_content = h2_overview.get("content", "").lower()
        if "completion overview" not in h2_content:
            errors.append(f"[X] heading2 should contain 'Completion Overview', got '{h2_overview.get('content')}'")
        else:
            checks_passed.append(f"[C] heading2 should contain 'Completion Overview', got '{h2_overview.get('content')}'")
        block_idx += 1
    
        # 6. Verify paragraph with stats
        if block_idx >= len(comparison_blocks_sorted):
            errors.append("[X] Missing statistics paragraph")
        else:
            checks_passed.append("[C] has statistics paragraph")
    
        stats_para = comparison_blocks_sorted[block_idx]
        if stats_para.get("type") != "paragraph":
            errors.append(f"[X] Block {block_idx} should be paragraph with stats, got {stats_para.get('type')}")
        else:
            checks_passed.append(f"[C] Block {block_idx} should be paragraph with stats, got {stats_para.get('type')}")
    
        stats_content = stats_para.get("content", "").lower()
    
        # Validate Q1 stats
        if "q1" not in stats_content:
            errors.append("[X] Stats paragraph should contain 'Q1'")
        else:
            checks_passed.append("[C] Stats paragraph should contain 'Q1'")
        if str(q1_total) not in stats_content:
            errors.append(f"[X] Stats paragraph should contain Q1 total goals: {q1_total}")
        else:
            checks_passed.append(f"[C] Stats paragraph should contain Q1 total goals: {q1_total}")
        if str(q1_completed) not in stats_content:
            errors.append(f"[X] Stats paragraph should contain Q1 completed: {q1_completed}")
        else:
            checks_passed.append(f"[C] Stats paragraph should contain Q1 completed: {q1_completed}")
    
        # Validate Q2 stats
        if "q2" not in stats_content:
            errors.append("[X] Stats paragraph should contain 'Q2'")
        else:
            checks_passed.append("[C] Stats paragraph should contain 'Q2'")
        if str(q2_total) not in stats_content:
            errors.append(f"[X] Stats paragraph should contain Q2 total goals: {q2_total}")
        else:
            checks_passed.append(f"[C] Stats paragraph should contain Q2 total goals: {q2_total}")
        if str(q2_completed) not in stats_content:
            errors.append(f"[X] Stats paragraph should contain Q2 completed: {q2_completed}")
        else:
            checks_passed.append(f"[C] Stats paragraph should contain Q2 completed: {q2_completed}")
    
        # Check for percentages (allow for rounding variations)
        if f"{q1_percentage}%" not in stats_content and f"{q1_percentage} %" not in stats_content:
            # Also check for decimal versions
            q1_pct_alt = round(q1_completed / q1_total * 100, 2) if q1_total > 0 else 0
            if f"{q1_pct_alt}%" not in stats_content and f"{int(q1_pct_alt)}%" not in stats_content:
                errors.append(f"[X] Stats paragraph should contain Q1 completion percentage (~{q1_percentage}%)")
            else:
                checks_passed.append(f"[C] Stats paragraph should contain Q1 completion percentage (~{q1_percentage}%)")
    
        block_idx += 1
    
        # 7. Verify heading2 '✅ Q1 Achievements'
        if block_idx >= len(comparison_blocks_sorted):
            errors.append("[X] Missing heading2 'Q1 Achievements' block")
        else:
            checks_passed.append("[C] has heading2 'Q1 Achievements' block")
    
        h2_achievements = comparison_blocks_sorted[block_idx]
        if h2_achievements.get("type") != "heading2":
            errors.append(f"[X] Block {block_idx} should be heading2 for Q1 Achievements, got {h2_achievements.get('type')}")
        else:
            checks_passed.append(f"[C] Block {block_idx} should be heading2 for Q1 Achievements, got {h2_achievements.get('type')}")
    
        achievements_content = h2_achievements.get("content", "").lower()
        if "q1 achievements" not in achievements_content:
            errors.append(f"[X] heading2 should contain 'Q1 Achievements', got '{h2_achievements.get('content')}'")
        else:
            checks_passed.append(f"[C] heading2 should contain 'Q1 Achievements', got '{h2_achievements.get('content')}'")
        block_idx += 1
    
        # 8. Verify bulleted list of checked Q1 todos
        q1_bullet_items = []
        while block_idx < len(comparison_blocks_sorted) and comparison_blocks_sorted[block_idx].get("type") == "bulletedList":
            q1_bullet_items.append(comparison_blocks_sorted[block_idx])
            block_idx += 1
    
        if len(q1_bullet_items) != q1_completed:
            errors.append(f"[X] Expected {q1_completed} bulleted list items for Q1 checked todos, found {len(q1_bullet_items)}")
        else:
            checks_passed.append(f"[C] Expected {q1_completed} bulleted list items for Q1 checked todos, found {len(q1_bullet_items)}")
    
        # Verify bulleted list contains checked Q1 todo texts
        q1_checked_texts = [b.get("content", "").lower() for b in q1_checked]
        for bullet_item in q1_bullet_items:
            bullet_content = bullet_item.get("content", "").lower()
            found_match = any(todo_text and todo_text in bullet_content for todo_text in q1_checked_texts)
            if not found_match:
                errors.append(f"[X] Q1 bulleted list item '{bullet_item.get('content')}' doesn't match any checked Q1 todo")
            else:
                checks_passed.append(f"[C] Q1 bulleted list item '{bullet_item.get('content')}' doesn't match any checked Q1 todo")
    
        # 9. Verify heading2 '🎯 Q2 Targets'
        if block_idx >= len(comparison_blocks_sorted):
            errors.append("[X] Missing heading2 'Q2 Targets' block")
        else:
            checks_passed.append("[C] has heading2 'Q2 Targets' block")
    
        h2_targets = comparison_blocks_sorted[block_idx]
        if h2_targets.get("type") != "heading2":
            errors.append(f"[X] Block {block_idx} should be heading2 for Q2 Targets, got {h2_targets.get('type')}")
        else:
            checks_passed.append(f"[C] Block {block_idx} should be heading2 for Q2 Targets, got {h2_targets.get('type')}")
    
        targets_content = h2_targets.get("content", "").lower()
        if "q2 targets" not in targets_content:
            errors.append(f"[X] heading2 should contain 'Q2 Targets', got '{h2_targets.get('content')}'")
        else:
            checks_passed.append(f"[C] heading2 should contain 'Q2 Targets', got '{h2_targets.get('content')}'")
        block_idx += 1
    
        # 10. Verify numbered list of all Q2 todos (checked and unchecked)
        q2_numbered_items = []
        while block_idx < len(comparison_blocks_sorted) and comparison_blocks_sorted[block_idx].get("type") == "numberedList":
            q2_numbered_items.append(comparison_blocks_sorted[block_idx])
            block_idx += 1
    
        if len(q2_numbered_items) != q2_total:
            errors.append(f"[X] Expected {q2_total} numbered list items for all Q2 todos, found {len(q2_numbered_items)}")
        else:
            checks_passed.append(f"[C] Expected {q2_total} numbered list items for all Q2 todos, found {len(q2_numbered_items)}")
    
        # Verify numbered list contains all Q2 todo texts
        q2_all_texts = [b.get("content", "").lower() for b in q2_todos]
        for numbered_item in q2_numbered_items:
            numbered_content = numbered_item.get("content", "").lower()
            found_match = any(todo_text and todo_text in numbered_content for todo_text in q2_all_texts)
            if not found_match:
                errors.append(f"[X] Q2 numbered list item '{numbered_item.get('content')}' doesn't match any Q2 todo")
            else:
                checks_passed.append(f"[C] Q2 numbered list item '{numbered_item.get('content')}' doesn't match any Q2 todo")
    
        # 11. Verify callout with blue_background, 📈 icon, and trend text
        if block_idx >= len(comparison_blocks_sorted):
            errors.append("[X] Missing callout block")
        else:
            checks_passed.append("[C] has callout block")
    
        callout_block = comparison_blocks_sorted[block_idx]
        if callout_block.get("type") != "callout":
            errors.append(f"[X] Block {block_idx} should be callout, got {callout_block.get('type')}")
        else:
            checks_passed.append(f"[C] Block {block_idx} should be callout, got {callout_block.get('type')}")
    
        callout_props = callout_block.get("properties", {})
    
        # Check blue background
        bg_color = callout_props.get("backgroundColor", "")
        if bg_color != "blue" and "blue" not in bg_color.lower():
            errors.append(f"[X] Callout should have blue_background, got '{bg_color}'")
        else:
            checks_passed.append(f"[C] Callout should have blue_background, got '{bg_color}'")
    
        # Check 📈 icon
        icon = callout_props.get("icon", "")
        if icon != "📈":
            errors.append(f"[X] Callout should have 📈 icon, got '{icon}'")
        else:
            checks_passed.append(f"[C] Callout should have 📈 icon, got '{icon}'")
    
        # Check content mentions quarter-over-quarter and improved/declined
        callout_content = callout_block.get("content", "").lower()
    
        if "quarter-over-quarter" not in callout_content and "quarter over quarter" not in callout_content:
            errors.append("[X] Callout should mention 'Quarter-over-quarter'")
        else:
            checks_passed.append("[C] Callout should mention 'Quarter-over-quarter'")
    
        if trend == "improved":
            if "improved" not in callout_content:
                errors.append(f"[X] Callout should indicate completion rate 'IMPROVED' (Q1: {q1_percentage}% -> Q2: {q2_percentage}%)")
            else:
                checks_passed.append(f"[C] Callout should indicate completion rate 'IMPROVED' (Q1: {q1_percentage}% -> Q2: {q2_percentage}%)")
        else:
            if "declined" not in callout_content:
                errors.append(f"[X] Callout should indicate completion rate 'DECLINED' (Q1: {q1_percentage}% -> Q2: {q2_percentage}%)")
            else:
                checks_passed.append(f"[C] Callout should indicate completion rate 'DECLINED' (Q1: {q1_percentage}% -> Q2: {q2_percentage}%)")
    
        # Check percentage difference is mentioned
        if str(diff) not in callout_content and str(int(diff)) not in callout_content:
            errors.append(f"[X] Callout should mention the percentage difference: {diff}%")
        else:
            checks_passed.append(f"[C] Callout should mention the percentage difference: {diff}%")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

    # -----------------------------------------------------------------------------
    # Task: weekly-standup-metrics-tracking
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_weekly_standup_metrics_tracking(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Weekly Metrics section insertion and todo prioritization.
    
    Goal: Navigate to 'Weekly Standup Template' page and insert a new metrics
    tracking section between 'What I plan to do next week' and 'Blockers' sections.
    Also add priority numbers to all unchecked todos.
    
    Validation steps (ordered):
    1. Find the 'Weekly Standup Template' page
    2. Find heading_2 'What I plan to do next week' section
    3. Find heading_2 'Blockers' section
    4. Verify heading_2 '📊 Weekly Metrics' exists between orders 7 and 8
    5. Verify code block with language 'markdown' exists after Weekly Metrics heading
    6. Verify code block contains exact content: '## Stats - Hours worked: - PRs reviewed: - Bugs fixed: '
    7. Verify callout with gray_background exists after code block
    8. Verify callout contains text 'Remember to update these metrics before the standup meeting!'
    9. Find all unchecked to-do blocks and verify each has priority number appended
       - First unchecked todo should end with '(1)'
       - Second unchecked todo should end with '(2)'
       - Third unchecked todo should end with '(3)'
    
    Weights: All-or-nothing (1.0 if all pass, 0.0 otherwise)
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    
    # 1. Find the Weekly Standup Template page
    try:
        standup_page = _find_page_by_title(final_state_backend, "Weekly Standup Template")
        if not standup_page:
            errors.append("[X] Weekly Standup Template page not found")
        else:
            checks_passed.append("[C] Weekly Standup Template page found")
    
        page_id = standup_page.get("_id")
        page_blocks = _get_blocks_for_page(final_state_backend, page_id)
    
        if not page_blocks:
            errors.append("[X] No blocks found on Weekly Standup Template page")
        else:
            checks_passed.append("[C] blocks found on Weekly Standup Template page")
    
        # Sort blocks by order
        page_blocks_sorted = sorted(page_blocks, key=lambda b: b.get("order", 0))
    
        # 2-3. Find key reference points
        what_plan_next_week_idx = None
        blockers_idx = None
        weekly_metrics_idx = None
        weekly_metrics_order = None
    
        for idx, block in enumerate(page_blocks_sorted):
            content = block.get("content", "")
            content_lower = content.lower()
            block_type = block.get("type", "")
            block_order = block.get("order", 0)
        
            if block_type == "heading2":
                if "what i plan to do next week" in content_lower:
                    what_plan_next_week_idx = idx
                elif content_lower == "blockers":
                    blockers_idx = idx
                elif "weekly metrics" in content_lower:
                    weekly_metrics_idx = idx
                    weekly_metrics_order = block_order
    
        # Verify 'What I plan to do next week' section exists
        if what_plan_next_week_idx is None:
            errors.append("[X] heading_2 'What I plan to do next week' not found")
        else:
            checks_passed.append("[C] heading_2 'What I plan to do next week' found")
    
        # Verify 'Blockers' section exists
        if blockers_idx is None:
            errors.append("[X] heading_2 'Blockers' not found")
        else:
            checks_passed.append("[C] heading_2 'Blockers' found")
    
        # 4. Verify Weekly Metrics heading exists
        if weekly_metrics_idx is None:
            errors.append("[X] heading_2 '📊 Weekly Metrics' not found")
        else:
            checks_passed.append("[C] heading_2 '📊 Weekly Metrics' found")

    
        # Verify Weekly Metrics is positioned between orders 7 and 8
        if weekly_metrics_order is None:
            errors.append("[X] Could not determine order of Weekly Metrics heading")
        else:
            checks_passed.append("[C] Could determine order of Weekly Metrics heading")
    
        # Get blockers order
        blockers_block = page_blocks_sorted[blockers_idx]
        blockers_order = blockers_block.get("order", 0)
    
        # Weekly metrics must be between what_plan_next_week section and blockers
        if weekly_metrics_idx <= what_plan_next_week_idx:
            errors.append(f"[X] '📊 Weekly Metrics' must appear AFTER 'What I plan to do next week' (Weekly Metrics at idx {weekly_metrics_idx}, What I plan at {what_plan_next_week_idx})")
        else:
            checks_passed.append(f"[C] '📊 Weekly Metrics' must appear AFTER 'What I plan to do next week' (Weekly Metrics at idx {weekly_metrics_idx}, What I plan at {what_plan_next_week_idx})")
    
        if weekly_metrics_idx >= blockers_idx:
            errors.append(f"[X] '📊 Weekly Metrics' must appear BEFORE 'Blockers' (Weekly Metrics at idx {weekly_metrics_idx}, Blockers at {blockers_idx})")
        else:
            checks_passed.append(f"[C] '📊 Weekly Metrics' must appear BEFORE 'Blockers' (Weekly Metrics at idx {weekly_metrics_idx}, Blockers at {blockers_idx})")
    
        # 5-6. Find code block after Weekly Metrics heading
        code_block = None
        code_block_idx = None
        for idx in range(weekly_metrics_idx + 1, len(page_blocks_sorted)):
            block = page_blocks_sorted[idx]
            block_type = block.get("type", "")
        
            if block_type == "code":
                code_block = block
                code_block_idx = idx
                break
            elif block_type in ["heading1", "heading2", "heading3"]:
                break
    
        if code_block is None:
            errors.append("[X] Code block not found after '📊 Weekly Metrics' heading")
        else:
            checks_passed.append("[C] Code block found after '📊 Weekly Metrics' heading")
    
        # Verify code block has language 'markdown'
        code_props = code_block.get("properties", {})
        code_language = code_props.get("language", "")
        if code_language.lower() != "markdown":
            errors.append(f"[X] Code block should have language 'markdown', got '{code_language}'")
        else:
            checks_passed.append(f"[C] Code block should have language 'markdown', got '{code_language}'")
    
        # Verify code block content
        expected_content = "## Stats - Hours worked: - PRs reviewed: - Bugs fixed: "
        code_content = code_block.get("content", "")
    
        # Normalize whitespace for comparison
        if expected_content not in code_content and code_content.replace("\n", " ").strip() != expected_content.strip():
            required_parts = ["## Stats", "Hours worked:", "PRs reviewed:", "Bugs fixed:"]
            missing = [part for part in required_parts if part not in code_content]
            if missing:
                errors.append(f"[X] Code block content missing required parts: {missing}. Got: '{code_content}'")
            else:
                checks_passed.append(f"[C] Code block content has required parts: {has}. Got: '{code_content}'")
    
        # 7-8. Find callout after code block
        callout_block = None
        for idx in range(code_block_idx + 1, len(page_blocks_sorted)):
            block = page_blocks_sorted[idx]
            block_type = block.get("type", "")
        
            if block_type == "callout":
                callout_block = block
                break
            elif block_type in ["heading1", "heading2", "heading3"]:
                break
    
        if callout_block is None:
            errors.append("[X] Callout block not found after code block")
        else:
            checks_passed.append("[C] Callout block found after code block")
    
        # Verify callout has gray_background
        callout_props = callout_block.get("properties", {})
        callout_bg = callout_props.get("backgroundColor", "")
        if "gray" not in callout_bg.lower():
            errors.append(f"[X] Callout should have gray_background, got '{callout_bg}'")
        else:
            checks_passed.append(f"[C] Callout should have gray_background, got '{callout_bg}'")
    
        # Verify callout content
        callout_content = callout_block.get("content", "")
        expected_callout_text = "Remember to update these metrics before the standup meeting!"
        if expected_callout_text not in callout_content:
            errors.append(f"[X] Callout should contain '{expected_callout_text}', got '{callout_content}'")
        else:
            checks_passed.append(f"[C] Callout should contain '{expected_callout_text}', got '{callout_content}'")
    
        # 9. Find all unchecked to-do blocks and verify priority numbers
        unchecked_todos = []
        for block in page_blocks_sorted:
            block_type = block.get("type", "")
            if block_type == "todo":
                props = block.get("properties", {})
                is_checked = props.get("checked", False)
                if not is_checked:
                    unchecked_todos.append(block)
    
        if len(unchecked_todos) == 0:
            errors.append("[X] No unchecked to-do blocks found on the page")
        else:
            checks_passed.append("[C] unchecked to-do blocks found on the page")
    
        # Verify each unchecked todo has priority number appended
        for i, todo in enumerate(unchecked_todos):
            expected_priority = f"({i + 1})"
            todo_content = todo.get("content", "")
        
            if not todo_content.rstrip().endswith(expected_priority):
                errors.append(f"[X] Unchecked todo #{i + 1} should end with '{expected_priority}', got: '{todo_content}'")
            else:
                checks_passed.append(f"[C] Unchecked todo #{i + 1} should end with '{expected_priority}', got: '{todo_content}'")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

    # -----------------------------------------------------------------------------
    # Task: external-resources-analytics
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_external_resources_analytics(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate external resources analytics section creation.
    
    Goal: Add a resource analytics section at the beginning of the 'External Resources & Links'
    page that summarizes bookmark counts and categories.
    
    Step-by-step validation plan:
    1. Find 'External Resources & Links' page (page-48)
    2. Get all blocks for the page
    3. Verify heading_2 '📊 Resource Analytics' exists as the first heading after title
    4. Count original heading_2 blocks (Documentation, Tools, Learning)
    5. Count all bookmark blocks in the page
    6. Verify callout with blue_background and '🔗' icon exists after the analytics heading
    7. Verify callout contains 'Total resources: X links across Y categories' with correct counts
    8. Verify heading_3 '🏷️ Category Distribution' exists after the callout
    9. Verify bulleted list with correct per-section bookmark counts
    
    Weights: All-or-nothing (1.0 if all pass, 0.0 otherwise)
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    
    # 1. Find External Resources & Links page
    try:
        external_resources_page = _find_page_by_title(final_state_backend, "External Resources & Links")
        if not external_resources_page:
            errors.append("[X] 'External Resources & Links' page not found")
        else:
            checks_passed.append("[C] 'External Resources & Links' page found")
    
        page_id = external_resources_page.get("_id")
    
        # 2. Get all blocks for the page
        page_blocks = _get_blocks_for_page(final_state_backend, page_id)
        if not page_blocks:
            errors.append("[X] No blocks found on 'External Resources & Links' page")
        else:
            checks_passed.append("[C] blocks found on 'External Resources & Links' page")
    
        # Sort blocks by order
        page_blocks_sorted = sorted(page_blocks, key=lambda b: b.get("order", 0))
    
        # 3. Count original heading_2 blocks and their bookmark counts
        # Original categories are: Documentation, Tools, Learning
        original_categories = {}
        current_category = None
    
        # Also track if we found the analytics section
        analytics_heading_idx = None
        analytics_heading_found = False
    
        # First pass: find the analytics heading
        for idx, block in enumerate(page_blocks_sorted):
            if block.get("type") == "heading2":
                content = block.get("content", "")
                if "resource analytics" in content.lower():
                    analytics_heading_idx = idx
                    analytics_heading_found = True
                    break
    
        if not analytics_heading_found:
            errors.append("[X] heading_2 '📊 Resource Analytics' not found")
        else:
            checks_passed.append("[C] heading_2 '📊 Resource Analytics' found")
    
        # Check that the analytics heading is near the start (after title/heading1)
        # It should appear before any of the original category headings
        first_original_category_idx = None
        for idx, block in enumerate(page_blocks_sorted):
            if block.get("type") == "heading2":
                content = block.get("content", "").lower()
                if content in ["documentation", "tools", "learning"]:
                    first_original_category_idx = idx
                    break
    
        if first_original_category_idx is not None and analytics_heading_idx >= first_original_category_idx:
            errors.append("[X] Analytics section must appear at the beginning of the page (after title), before original category sections")
        else:
            checks_passed.append("[C] Analytics section must appear at the beginning of the page (after title), before original category sections")
    
        # 4. Count bookmarks per original category
        # Build a mapping of categories to their bookmark counts
        for idx, block in enumerate(page_blocks_sorted):
            block_type = block.get("type", "")
            content = block.get("content", "")
        
            if block_type == "heading2":
                content_lower = content.lower()
                # Only count original categories, not the new analytics heading
                if content_lower in ["documentation", "tools", "learning"]:
                    current_category = content  # Keep original case for display
                    if current_category not in original_categories:
                        original_categories[current_category] = 0
                elif "resource analytics" in content_lower:
                    # Skip analytics section's children
                    current_category = None
            elif block_type == "bookmark" and current_category is not None:
                original_categories[current_category] = original_categories.get(current_category, 0) + 1
    
        # Calculate totals
        total_bookmarks = sum(original_categories.values())
        total_categories = len(original_categories)
    
        if total_categories == 0:
            errors.append("[X] No original category sections found (expected Documentation, Tools, Learning)")
        else:
            checks_passed.append("[C] original category sections found (expected Documentation, Tools, Learning)")
    
        # 5. Validate the structure after the analytics heading
        # Expected order: heading2 (analytics) -> callout -> heading3 -> bulleted list items
    
        # Find blocks after analytics heading
        blocks_after_analytics = page_blocks_sorted[analytics_heading_idx + 1:]
    
        if not blocks_after_analytics:
            errors.append("[X] No blocks found after '📊 Resource Analytics' heading")
        else:
            checks_passed.append("[C] blocks found after '📊 Resource Analytics' heading")
    
        # 6. Check for callout with blue_background and 🔗 icon
        callout_block = None
        callout_idx = None
        for idx, block in enumerate(blocks_after_analytics):
            if block.get("type") == "callout":
                callout_block = block
                callout_idx = idx
                break
            # Stop if we hit another heading2 (meaning we passed the analytics section)
            if block.get("type") == "heading2" and "resource analytics" not in block.get("content", "").lower():
                break
    
        if not callout_block:
            errors.append("[X] Callout block not found after '📊 Resource Analytics' heading")
        else:
            checks_passed.append("[C] Callout block found after '📊 Resource Analytics' heading")
    
        callout_props = callout_block.get("properties", {})
        callout_bg = callout_props.get("backgroundColor", "")
    
        if "blue" not in callout_bg.lower():
            errors.append(f"[X] Callout should have blue_background, got '{callout_bg}'")
        else:
            checks_passed.append(f"[C] Callout should have blue_background, got '{callout_bg}'")
    
        callout_icon = callout_props.get("icon", "")
        if callout_icon != "🔗":
            errors.append(f"[X] Callout should have '🔗' icon, got '{callout_icon}'")
        else:
            checks_passed.append(f"[C] Callout should have '🔗' icon, got '{callout_icon}'")
    
        # 7. Verify callout content contains accurate counts
        callout_content = callout_block.get("content", "")
        callout_content_lower = callout_content.lower()
    
        # Check for total resources count
        expected_total_pattern = f"total resources: {total_bookmarks} links"
        if expected_total_pattern.lower() not in callout_content_lower:
            errors.append(f"[X] Callout should contain '{expected_total_pattern}', got '{callout_content}'")
        else:
            checks_passed.append(f"[C] Callout should contain '{expected_total_pattern}', got '{callout_content}'")
    
        # Check for category count
        expected_category_pattern = f"across {total_categories} categories"
        if expected_category_pattern.lower() not in callout_content_lower:
            errors.append(f"[X] Callout should contain '{expected_category_pattern}', got '{callout_content}'")
        else:
            checks_passed.append(f"[C] Callout should contain '{expected_category_pattern}', got '{callout_content}'")
    
        # 8. Check for heading_3 '🏷️ Category Distribution'
        category_distribution_heading = None
        category_heading_idx = None
        for idx, block in enumerate(blocks_after_analytics[callout_idx + 1:], start=callout_idx + 1):
            if block.get("type") == "heading3":
                content = block.get("content", "")
                if "category distribution" in content.lower():
                    category_distribution_heading = block
                    category_heading_idx = idx
                    break
            # Stop if we hit a heading2 from original categories
            if block.get("type") == "heading2":
                content_lower = block.get("content", "").lower()
                if content_lower in ["documentation", "tools", "learning"]:
                    break
    
        if not category_distribution_heading:
            errors.append("[X] heading_3 '🏷️ Category Distribution' not found after callout")
        else:
            checks_passed.append("[C] heading_3 '🏷️ Category Distribution' found after callout")
    
        # 9. Check for bulleted list with section counts
        bulleted_items = []
        for idx, block in enumerate(blocks_after_analytics[category_heading_idx + 1:], start=category_heading_idx + 1):
            if block.get("type") == "bulletedList":
                bulleted_items.append(block)
            elif block.get("type") in ["heading2", "heading3", "divider"]:
                # Stop at next section
                break
    
        if len(bulleted_items) < total_categories:
            errors.append(f"[X] Expected at least {total_categories} bulleted list items for categories, found {len(bulleted_items)}")
        else:
            checks_passed.append(f"[C] Expected at least {total_categories} bulleted list items for categories, found {len(bulleted_items)}")
    
        # Verify each category appears in the bulleted list with correct count
        found_categories = {}
        for item in bulleted_items:
            content = item.get("content", "")
        
            # Check for each original category
            for category_name, count in original_categories.items():
                if category_name.lower() in content.lower():
                    # Check if the count is mentioned
                    if str(count) in content and "resource" in content.lower():
                        found_categories[category_name] = count
    
        # Verify all original categories are represented
        for category_name, expected_count in original_categories.items():
            if category_name not in found_categories:
                errors.append(f"[X] Bulleted list missing entry for '{category_name}: {expected_count} resources'")
            else:
                checks_passed.append(f"[C] Bulleted list has entry for '{category_name}: {expected_count} resources'")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

    # -----------------------------------------------------------------------------
    # Task: weekly-standup-template-enhancement
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_weekly_standup_template_enhancement(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate weekly standup template enhancement task.
    
    Goal: Enhance the Weekly Standup Template page with precise additions:
    1. Green callout after 'What I plan to do next week' heading but before its todos
    2. Time Tracking section between 'What I did this week' and 'What I plan to do next week'
    3. Weekly Metrics section at the end with divider and three todos
    
    Validation steps (ordered):
    1. Find the 'Weekly Standup Template' page (page-9)
    2. Get all blocks sorted by order
    3. Verify heading_3 '⏱️ Time Tracking' exists AFTER 'What I did this week' todos 
       but BEFORE 'What I plan to do next week' heading
    4. Verify paragraph 'Hours spent on tasks this week: [PLACEHOLDER]' after Time Tracking heading
    5. Verify callout with green_background, icon '🎯', and text 
       'Remember: Break down large tasks into smaller, measurable goals.' appears 
       AFTER 'What I plan to do next week' heading but BEFORE its todo items
    6. Verify a divider block appears after the 'Blockers' section (after block-9-10)
    7. Verify heading_2 '📈 Weekly Metrics' appears after the divider
    8. Verify three todo blocks with exact texts appear after Weekly Metrics heading:
       - '📊 Update project dashboard with progress'
       - '📧 Send weekly summary to stakeholders'
       - '🔄 Schedule 1:1s with team members'
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    
    # 1. Find Weekly Standup Template page (page-9)
    try:
        standup_page = _find_page_by_title(final_state_backend, "Weekly Standup Template")
        if not standup_page:
            errors.append("[X] Weekly Standup Template page not found")
        else:
            checks_passed.append("[C] Weekly Standup Template page found")
    
        page_id = standup_page.get("_id")
        page_blocks = _get_blocks_for_page(final_state_backend, page_id)
    
        if not page_blocks:
            errors.append("[X] No blocks found on Weekly Standup Template page")
        else:
            checks_passed.append("[C] blocks found on Weekly Standup Template page")
    
        # Sort blocks by order to ensure correct sequence
        page_blocks_sorted = sorted(page_blocks, key=lambda b: b.get("order", 0))
    
        # 2. Find key reference points in the page
        what_i_did_heading_idx = None
        what_i_did_last_todo_idx = None
        what_i_plan_heading_idx = None
        blockers_heading_idx = None
        blockers_last_item_idx = None
        time_tracking_heading_idx = None
        time_tracking_paragraph_idx = None
        green_callout_idx = None
        what_i_plan_first_todo_idx = None
        divider_after_blockers_idx = None
        weekly_metrics_heading_idx = None
    
        for idx, block in enumerate(page_blocks_sorted):
            block_id = block.get("_id", "")
            content = block.get("content", "")
            content_lower = content.lower()
            block_type = block.get("type", "")
            properties = block.get("properties", {})
        
            # Find 'What I did this week' heading (block-9-3)
            if block_type == "heading2" and "what i did this week" in content_lower:
                what_i_did_heading_idx = idx
        
            # Find block-9-5 (last todo under 'What I did this week')
            if block_id == "block-9-5" or "reviewed pull requests from team members" in content_lower:
                what_i_did_last_todo_idx = idx
        
            # Find 'What I plan to do next week' heading (block-9-6)
            if block_type == "heading2" and "what i plan to do next week" in content_lower:
                what_i_plan_heading_idx = idx
        
            # Find first todo under 'What I plan to do next week' (block-9-7)
            if block_id == "block-9-7" or "start working on feature y" in content_lower:
                what_i_plan_first_todo_idx = idx
        
            # Find 'Blockers' heading (block-9-9)
            if block_type == "heading2" and "blockers" in content_lower:
                blockers_heading_idx = idx
        
            # Find block-9-10 (last item under Blockers)
            if block_id == "block-9-10" or "waiting for design review on component z" in content_lower:
                blockers_last_item_idx = idx
        
            # Find the new '⏱️ Time Tracking' heading
            if block_type in ["heading3", "heading_3"] and "time tracking" in content_lower:
                time_tracking_heading_idx = idx
        
            # Find the time tracking paragraph
            if block_type == "paragraph" and "hours spent on tasks this week" in content_lower:
                time_tracking_paragraph_idx = idx
        
            # Find the green callout with goal reminder
            if block_type == "callout":
                bg_color = properties.get("backgroundColor", "")
                icon = properties.get("icon", "")
                if ("green" in bg_color.lower() and 
                    "🎯" in icon and 
                    "break down large tasks" in content_lower):
                    green_callout_idx = idx
        
            # Find divider after blockers
            if block_type == "divider" and blockers_last_item_idx is not None and idx > blockers_last_item_idx:
                if divider_after_blockers_idx is None:
                    divider_after_blockers_idx = idx
        
            # Find Weekly Metrics heading
            if block_type in ["heading2", "heading_2"] and "weekly metrics" in content_lower:
                weekly_metrics_heading_idx = idx
    
        # Validation: ensure we found the reference points
        if what_i_did_last_todo_idx is None:
            errors.append("[X] 'What I did this week' section last todo (block-9-5) not found")
        else:
            checks_passed.append("[C] 'What I did this week' section last todo (block-9-5) found")
    
        if what_i_plan_heading_idx is None:
            errors.append("[X] 'What I plan to do next week' heading not found")
        else:
            checks_passed.append("[C] 'What I plan to do next week' heading found")
    
        if what_i_plan_first_todo_idx is None:
            errors.append("[X] 'What I plan to do next week' first todo (block-9-7) not found")
        else:
            checks_passed.append("[C] 'What I plan to do next week' first todo (block-9-7) found")
    
        if blockers_last_item_idx is None:
            errors.append("[X] 'Blockers' section last item (block-9-10) not found")
        else:
            checks_passed.append("[C] 'Blockers' section last item (block-9-10) found")
    
        # 3. Verify heading_3 '⏱️ Time Tracking' exists in correct position
        if time_tracking_heading_idx is None:
            errors.append("[X] heading_3 '⏱️ Time Tracking' not found")
        else:
            checks_passed.append("[C] heading_3 '⏱️ Time Tracking' found")
    
        time_tracking_block = page_blocks_sorted[time_tracking_heading_idx]
        time_tracking_content = time_tracking_block.get("content", "")
    
        # Check position: must be after 'What I did this week' last todo but before 'What I plan to do next week' heading
        if time_tracking_heading_idx <= what_i_did_last_todo_idx:
            errors.append("[X] Time Tracking heading must be AFTER 'What I did this week' last todo")
        else:
            checks_passed.append("[C] Time Tracking heading must be AFTER 'What I did this week' last todo")
    
        if time_tracking_heading_idx >= what_i_plan_heading_idx:
            errors.append("[X] Time Tracking heading must be BEFORE 'What I plan to do next week' heading")
        else:
            checks_passed.append("[C] Time Tracking heading must be BEFORE 'What I plan to do next week' heading")
    
        # 4. Verify paragraph 'Hours spent on tasks this week: [PLACEHOLDER]' after Time Tracking heading
        if time_tracking_paragraph_idx is None:
            errors.append("[X] Paragraph 'Hours spent on tasks this week: [PLACEHOLDER]' not found")
        else:
            checks_passed.append("[C] Paragraph 'Hours spent on tasks this week: [PLACEHOLDER]' found")
    
        time_tracking_para_block = page_blocks_sorted[time_tracking_paragraph_idx]
        time_tracking_para_content = time_tracking_para_block.get("content", "")
    
        # Check for PLACEHOLDER
        if "[placeholder]" not in time_tracking_para_content.lower():
            errors.append("[X] Time tracking paragraph should contain '[PLACEHOLDER]'")
        else:
            checks_passed.append("[C] Time tracking paragraph should contain '[PLACEHOLDER]'")
    
        if time_tracking_paragraph_idx <= time_tracking_heading_idx:
            errors.append("[X] Time tracking paragraph must be AFTER Time Tracking heading")
        else:
            checks_passed.append("[C] Time tracking paragraph must be AFTER Time Tracking heading")
    
        if time_tracking_paragraph_idx >= what_i_plan_heading_idx:
            errors.append("[X] Time tracking paragraph must be BEFORE 'What I plan to do next week' heading")
        else:
            checks_passed.append("[C] Time tracking paragraph must be BEFORE 'What I plan to do next week' heading")
    
        # 5. Verify green callout in correct position
        if green_callout_idx is None:
            errors.append("[X] Green callout with '🎯' icon and goal reminder text not found")
        else:
            checks_passed.append("[C] Green callout with '🎯' icon and goal reminder text found")
    
        green_callout_block = page_blocks_sorted[green_callout_idx]
        green_callout_content = green_callout_block.get("content", "")
        green_callout_props = green_callout_block.get("properties", {})
    
        # Verify callout properties
        bg_color = green_callout_props.get("backgroundColor", "")
        if "green" not in bg_color.lower():
            errors.append("[X] Goal reminder callout must have green_background")
        else:
            checks_passed.append("[C] Goal reminder callout must have green_background")
    
        icon = green_callout_props.get("icon", "")
        if "🎯" not in icon:
            errors.append("[X] Goal reminder callout must have 🎯 icon")
        else:
            checks_passed.append("[C] Goal reminder callout must have 🎯 icon")
    
        # Verify exact text
        if "remember" not in green_callout_content.lower() or "break down large tasks into smaller, measurable goals" not in green_callout_content.lower():
            errors.append("[X] Callout text should be 'Remember: Break down large tasks into smaller, measurable goals.'")
        else:
            checks_passed.append("[C] Callout text should be 'Remember: Break down large tasks into smaller, measurable goals.'")
    
        # Check position: must be after 'What I plan to do next week' heading but before its first todo
        if green_callout_idx <= what_i_plan_heading_idx:
            errors.append("[X] Green callout must be AFTER 'What I plan to do next week' heading")
        else:
            checks_passed.append("[C] Green callout must be AFTER 'What I plan to do next week' heading")
    
        if green_callout_idx >= what_i_plan_first_todo_idx:
            errors.append("[X] Green callout must be BEFORE 'What I plan to do next week' first todo")
        else:
            checks_passed.append("[C] Green callout must be BEFORE 'What I plan to do next week' first todo")
    
        # 6. Verify divider after Blockers section
        if divider_after_blockers_idx is None:
            errors.append("[X] Divider not found after 'Blockers' section")
        else:
            checks_passed.append("[C] Divider found after 'Blockers' section")
    
        if divider_after_blockers_idx <= blockers_last_item_idx:
            errors.append("[X] Divider must be AFTER 'Blockers' last item")
        else:
            checks_passed.append("[C] Divider must be AFTER 'Blockers' last item")
    
        # 7. Verify heading_2 '📈 Weekly Metrics' after divider
        if weekly_metrics_heading_idx is None:
            errors.append("[X] heading_2 '📈 Weekly Metrics' not found")
        else:
            checks_passed.append("[C] heading_2 '📈 Weekly Metrics' found")
    
        weekly_metrics_block = page_blocks_sorted[weekly_metrics_heading_idx]
        weekly_metrics_content = weekly_metrics_block.get("content", "")
    
        if weekly_metrics_heading_idx <= divider_after_blockers_idx:
            errors.append("[X] Weekly Metrics heading must be AFTER the divider")
        else:
            checks_passed.append("[C] Weekly Metrics heading must be AFTER the divider")
    
        # 8. Verify three todo blocks after Weekly Metrics heading
        expected_todos = [
            "📊 update project dashboard with progress",
            "📧 send weekly summary to stakeholders",
            "🔄 schedule 1:1s with team members"
        ]
    
        found_todos = []
        for idx in range(weekly_metrics_heading_idx + 1, len(page_blocks_sorted)):
            block = page_blocks_sorted[idx]
            if block.get("type") == "todo":
                todo_content = block.get("content", "").lower()
                found_todos.append(todo_content)
    
        # Verify all expected todos are found
        for expected_todo in expected_todos:
            found = False
            for found_todo in found_todos:
                # Check for the key identifying parts
                if expected_todo.split()[0] in found_todo:  # Check emoji
                    expected_text = expected_todo.split(maxsplit=1)[1] if " " in expected_todo else expected_todo
                    if expected_text in found_todo:
                        found = True
                        break
            if not found:
                errors.append(f"[X] Todo '{expected_todo}' not found after Weekly Metrics heading")
            else:
                checks_passed.append(f"[C] Todo '{expected_todo}' found after Weekly Metrics heading")
    
        if len(found_todos) < 3:
            errors.append(f"[X] Expected 3 todos after Weekly Metrics heading, found {len(found_todos)}")
        else:
            checks_passed.append(f"[C] Found 3 todos after Weekly Metrics heading as expected")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_agent_project_roadmap_reorganization_2(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate comprehensive reorganization of the Project Roadmap page.
    
    Goal: Reorganize Project Roadmap with archive structure and new content blocks.
    
    Validation steps:
    1. Verify 'Quarterly Archive' page exists as child of 'Project Roadmap'
    2. Verify 'Q1 Goals' and 'Q2 Goals' are now children of 'Quarterly Archive' (moved)
    3. In 'Project Roadmap' page, verify heading_1 '🗺️ 2024 Product Roadmap'
    4. Verify heading_2 '📋 Active Initiatives'
    5. Verify callout with blue_background, icon '🚀', text 'Current quarter focus: Q3 2024'
    6. Verify three unchecked to-do blocks with exact text
    7. Verify heading_2 '🔗 Quick Links'
    8. Verify bulleted list with exactly three items
    
    Weights: All checks must pass (binary 0/1).
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    
    # 1. Find 'Project Roadmap' page
    try:
        project_roadmap = _find_page_by_title(final_state_backend, "Project Roadmap")
        if not project_roadmap:
            errors.append("[X] Project Roadmap page not found")
        else:
            checks_passed.append("[C] Project Roadmap page found")

        project_roadmap_id = project_roadmap.get("_id")

        # 2. Verify 'Quarterly Archive' page exists as child of 'Project Roadmap'
        quarterly_archive = _find_page_by_title_pattern_and_parent(final_state_backend, "Quarterly Archive", project_roadmap_id)
        if not quarterly_archive:
            errors.append("[X] '📊 Quarterly Archive' page not found as child of 'Project Roadmap'")
        else:
            checks_passed.append("[C] '📊 Quarterly Archive' page found as child of 'Project Roadmap'")

        quarterly_archive_id = quarterly_archive.get("_id")

        # 3. Verify 'Q1 Goals' is now a child of 'Quarterly Archive'
        q1_goals = _find_page_by_title_pattern_and_parent(final_state_backend, "Q1 Goals", quarterly_archive_id)
        if not q1_goals:
            errors.append("[X] 'Q1 Goals' page not found as child of 'Quarterly Archive'")
        else:
            checks_passed.append("[C] 'Q1 Goals' page found as child of 'Quarterly Archive'")

        # 4. Verify 'Q2 Goals' is now a child of 'Quarterly Archive'
        q2_goals = _find_page_by_title_pattern_and_parent(final_state_backend, "Q2 Goals", quarterly_archive_id)
        if not q2_goals:
            errors.append("[X] 'Q2 Goals' page not found as child of 'Quarterly Archive'")
        else:
            checks_passed.append("[C] 'Q2 Goals' page found as child of 'Quarterly Archive'")

        # 5. Get blocks from Project Roadmap page
        roadmap_blocks = _get_blocks_for_page(final_state_backend, project_roadmap_id)
    
        # Sort blocks by order if available
        roadmap_blocks_sorted = sorted(roadmap_blocks, key=lambda b: b.get("order", 0))
    
        if len(roadmap_blocks_sorted) < 9:  # Minimum: h1 + h2 + callout + 3 todos + h2 + 3 bullets
            errors.append(f"[X] Project Roadmap page has too few blocks ({len(roadmap_blocks_sorted)}), expected at least 9")
        else:
            checks_passed.append(f"[C] Project Roadmap page has too few blocks ({len(roadmap_blocks_sorted)}), expected at least 9")
    
        # 6. Verify heading_1 '🗺️ 2024 Product Roadmap'
        heading1_found = False
        for block in roadmap_blocks_sorted:
            if block.get("type") == "heading1":
                content = block.get("content", "").lower()
                if "2024 product roadmap" in content:
                    heading1_found = True
                    break
    
        if not heading1_found:
            errors.append("[X] heading_1 '🗺️ 2024 Product Roadmap' not found in Project Roadmap page")
        else:
            checks_passed.append("[C] heading_1 '🗺️ 2024 Product Roadmap' found in Project Roadmap page")
    
        # 7. Verify heading_2 '📋 Active Initiatives'
        active_initiatives_idx = None
        for idx, block in enumerate(roadmap_blocks_sorted):
            if block.get("type") == "heading2":
                content = block.get("content", "").lower()
                if "active initiatives" in content:
                    active_initiatives_idx = idx
                    break
    
        if active_initiatives_idx is None:
            errors.append("[X] heading_2 '📋 Active Initiatives' not found in Project Roadmap page")
        else:
            checks_passed.append("[C] heading_2 '📋 Active Initiatives' found in Project Roadmap page")
    
        # 8. Verify callout with blue_background, icon '🚀', text 'Current quarter focus: Q3 2024'
        callout_found = False
        callout_idx = None
        for idx, block in enumerate(roadmap_blocks_sorted):
            if block.get("type") == "callout":
                props = block.get("properties", {})
                bg_color = props.get("backgroundColor", "")
                icon = props.get("icon", "")
                content = block.get("content", "").lower()
            
                # Check blue background
                if "blue" not in bg_color.lower():
                    continue
            
                # Check icon
                if "🚀" not in icon:
                    continue
            
                # Check content
                if "current quarter focus" in content and "q3 2024" in content:
                    callout_found = True
                    callout_idx = idx
                    break
    
        if not callout_found:
            errors.append("[X] Callout with blue_background, '🚀' icon, and 'Current quarter focus: Q3 2024' not found")
        else:
            checks_passed.append("[C] Callout with blue_background, '🚀' icon, and 'Current quarter focus: Q3 2024' found")
    
        # 9. Verify three unchecked to-do blocks with exact text
        expected_todos = [
            "🎯 define q3 okrs and success metrics",
            "📐 complete technical architecture review",
            "🔄 migrate historical goals to archive"
        ]
    
        found_todos = []
        for block in roadmap_blocks_sorted:
            if block.get("type") == "todo":
                content = block.get("content", "").lower()
                checked = block.get("properties", {}).get("checked", False)
            
                for expected in expected_todos:
                    # Check content match (flexible)
                    expected_text_parts = expected.split(maxsplit=1)
                    emoji = expected_text_parts[0] if len(expected_text_parts) > 0 else ""
                    text = expected_text_parts[1] if len(expected_text_parts) > 1 else expected
                
                    if text in content or expected in content:
                        if checked:
                            errors.append(f"[X] Todo '{expected}' should be unchecked")
                        else:
                            checks_passed.append(f"[C] Todo '{expected}' should be unchecked")
                        found_todos.append(expected)
                        break
    
        # Remove duplicates
        found_todos = list(set(found_todos))
    
        if len(found_todos) < 3:
            missing = [t for t in expected_todos if t not in found_todos]
            errors.append(f"[X] Missing to-do blocks: {missing}")
        else:
            checks_passed.append(f"[C] has to-do blocks: {has}")
    
        # 10. Verify heading_2 '🔗 Quick Links'
        quick_links_idx = None
        for idx, block in enumerate(roadmap_blocks_sorted):
            if block.get("type") == "heading2":
                content = block.get("content", "").lower()
                if "quick links" in content:
                    quick_links_idx = idx
                    break
    
        if quick_links_idx is None:
            errors.append("[X] heading_2 '🔗 Quick Links' not found in Project Roadmap page")
        else:
            checks_passed.append("[C] heading_2 '🔗 Quick Links' found in Project Roadmap page")
    
        # 11. Verify bulleted list with exactly three items after Quick Links heading
        expected_bullets = [
            "view quarterly archive",
            "view performance metrics",
            "view team assignments"
        ]
    
        found_bullets = []
        for idx in range(quick_links_idx + 1, len(roadmap_blocks_sorted)):
            block = roadmap_blocks_sorted[idx]
            if block.get("type") == "bulleted_list":
                content = block.get("content", "").lower()
                for expected in expected_bullets:
                    if expected in content:
                        found_bullets.append(expected)
                        break
            # Stop if we hit another heading
            elif block.get("type") in ["heading1", "heading2", "heading3"]:
                break
    
        # Remove duplicates
        found_bullets = list(set(found_bullets))
    
        if len(found_bullets) < 3:
            missing = [b for b in expected_bullets if b not in found_bullets]
            errors.append(f"[X] Missing bulleted list items in Quick Links: {missing}")
        else:
            checks_passed.append(f"[C] has bulleted list items in Quick Links: {has}")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

    # -----------------------------------------------------------------------------
    # Task: project-status-dashboard
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_project_status_dashboard(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Project Status Dashboard creation.
    
    Goal: Create a new page '🎯 Project Status Dashboard' under 'Project Roadmap',
    analyzing all pages with 'Project' in the title within workspace-1.
    
    Validation steps (ordered):
    1. Find 'Project Roadmap' page
    2. Verify '🎯 Project Status Dashboard' exists as child of Project Roadmap
    3. Verify heading1 '🎯 Project Status Dashboard'
    4. Verify yellow callout with 📊 icon showing correct summary stats
    5. For each project page (non-archived, workspace-1):
       - heading2 with icon and title
       - Paragraph 'Page ID: [page-id]'
       - Callout (green if favorited, gray if not) with 'Priority: High/Normal'
       - Text 'Content blocks: [X]'
       - If has children, bulletedList with child page titles
    
    Weights: All-or-nothing (1.0 if all pass, 0.0 otherwise)
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    
    # 1. Find Project Roadmap page
    try:
        project_roadmap = _find_page_by_title(final_state_backend, "Project Roadmap")
        if not project_roadmap:
            errors.append("[X] Project Roadmap page not found")
        else:
            checks_passed.append("[C] Project Roadmap page found")
    
        project_roadmap_id = project_roadmap.get("_id")
    
        # 2. Find '🎯 Project Status Dashboard' as child of Project Roadmap
        dashboard_page = _find_page_by_title_pattern_and_parent(final_state_backend, "Project Status Dashboard", project_roadmap_id)
        if not dashboard_page:
            errors.append("[X] '🎯 Project Status Dashboard' not found as child of 'Project Roadmap'")
        else:
            checks_passed.append("[C] '🎯 Project Status Dashboard' found as child of 'Project Roadmap'")

        dashboard_page_id = dashboard_page.get("_id")

        # Get all blocks for the dashboard page
        dashboard_blocks = _get_blocks_for_page(final_state_backend, dashboard_page_id)
        if not dashboard_blocks:
            errors.append("[X] Dashboard page has no blocks")
        else:
            checks_passed.append("[C] Dashboard page has blocks")
    
        # Sort blocks by order
        dashboard_blocks_sorted = sorted(dashboard_blocks, key=lambda b: b.get("order", 0))
    
        # 3. Verify heading1 '🎯 Project Status Dashboard'
        h1_found = False
        for block in dashboard_blocks_sorted:
            if block.get("type") == "heading1":
                content = block.get("content", "").lower()
                if "project status dashboard" in content:
                    h1_found = True
                    break
    
        if not h1_found:
            errors.append("[X] heading1 '🎯 Project Status Dashboard' not found")
        else:
            checks_passed.append("[C] heading1 '🎯 Project Status Dashboard' found")
    
        # Identify all project pages in workspace-1 (non-archived, with 'Project' in title)
        project_pages_result = final_state_backend.query({
            "collection": "pages",
            "filter": {
                "title": {"$regex": "project", "$options": "i"},
                "workspaceId": "workspace-1",
                "isArchived": {"$ne": True}
            }
        })
        project_pages_raw = project_pages_result if isinstance(project_pages_result, list) else []
        # Exclude the dashboard page itself
        project_pages = [p for p in project_pages_raw if p.get("_id") != dashboard_page_id]

        if not project_pages:
            errors.append("[X] No project pages found in workspace-1")
        else:
            checks_passed.append("[C] project pages found in workspace-1")

        # Calculate expected summary stats
        total_projects = len(project_pages)
        high_priority_count = sum(1 for p in project_pages if p.get("isFavorite", False))

        # Count pages with sub-projects (child pages)
        with_subprojects_count = 0
        for proj_page in project_pages:
            proj_id = proj_page.get("_id")
            child_pages = _get_child_pages(final_state_backend, proj_id)
            # Filter out archived children
            active_children = [p for p in child_pages if not p.get("isArchived", False)]
            if active_children:
                with_subprojects_count += 1
    
        # 4. Verify yellow callout with 📊 icon showing summary stats
        summary_callout_found = False
        for block in dashboard_blocks_sorted:
            if block.get("type") == "callout":
                props = block.get("properties", {})
                bg_color = props.get("backgroundColor", "")
                icon = props.get("icon", "")
                content = block.get("content", "").lower()
            
                if "yellow" in bg_color.lower() and "📊" in icon:
                    # Check for summary stats in content
                    if "total projects tracked" in content:
                        # Verify the numbers
                        if str(total_projects) in content and str(high_priority_count) in content and str(with_subprojects_count) in content:
                            summary_callout_found = True
                            break
    
        if not summary_callout_found:
            errors.append(f"[X] Yellow callout with 📊 icon and correct summary stats not found. Expected: Total: {total_projects}, High priority: {high_priority_count}, With sub-projects: {with_subprojects_count}")
        else:
            checks_passed.append(f"[C] Yellow callout with 📊 icon and correct summary stats found. Expected: Total: {total_projects}, High priority: {high_priority_count}, With sub-projects: {with_subprojects_count}")
    
        # 5. Validate each project section
        for proj_page in project_pages:
            proj_id = proj_page.get("_id")
            proj_title = proj_page.get("title", "")
            proj_icon = proj_page.get("icon", "")
            is_favorited = proj_page.get("isFavorite", False)
        
            # Count blocks for this project page
            proj_blocks = _get_blocks_for_page(final_state_backend, proj_id)
            block_count = len(proj_blocks)

            # Get child pages
            child_pages_all = _get_child_pages(final_state_backend, proj_id)
            child_pages = [p for p in child_pages_all if not p.get("isArchived", False)]
        
            # 5a. Find heading2 with icon and title
            h2_found = False
            for block in dashboard_blocks_sorted:
                if block.get("type") == "heading2":
                    content = block.get("content", "")
                    # Check if title is in the heading (case-insensitive)
                    if proj_title.lower() in content.lower():
                        h2_found = True
                        break
        
            if not h2_found:
                errors.append(f"[X] heading2 for project '{proj_title}' not found")
            else:
                checks_passed.append(f"[C] heading2 for project '{proj_title}' found")
        
            # 5b. Find paragraph with 'Page ID: [page-id]'
            page_id_found = False
            for block in dashboard_blocks_sorted:
                if block.get("type") == "paragraph":
                    content = block.get("content", "").lower()
                    if "page id" in content and proj_id.lower() in content:
                        page_id_found = True
                        break
        
            if not page_id_found:
                errors.append(f"[X] Paragraph 'Page ID: {proj_id}' not found for project '{proj_title}'")
            else:
                checks_passed.append(f"[C] Paragraph 'Page ID: {proj_id}' found for project '{proj_title}'")
        
            # 5c. Find priority callout (green if favorited, gray if not)
            priority_callout_found = False
            expected_bg = "green" if is_favorited else "gray"
            expected_priority = "high" if is_favorited else "normal"
        
            for block in dashboard_blocks_sorted:
                if block.get("type") == "callout":
                    props = block.get("properties", {})
                    bg_color = props.get("backgroundColor", "").lower()
                    content = block.get("content", "").lower()
                
                    # Check if this callout is for this project (by checking proximity or content)
                    if expected_bg in bg_color and "priority" in content and expected_priority in content:
                        priority_callout_found = True
                        break
        
            if not priority_callout_found:
                errors.append(f"[X] Priority callout ({expected_bg}_background, 'Priority: {'High' if is_favorited else 'Normal'}') not found for project '{proj_title}'")
            else:
                checks_passed.append(f"[C] Priority callout ({expected_bg}_background, 'Priority: {'High' if is_favorited else 'Normal'}') found for project '{proj_title}'")
        
            # 5d. Find text 'Content blocks: [X]'
            block_count_found = False
            for block in dashboard_blocks_sorted:
                if block.get("type") == "paragraph":
                    content = block.get("content", "").lower()
                    if "content blocks" in content and str(block_count) in content:
                        block_count_found = True
                        break
        
            if not block_count_found:
                errors.append(f"[X] Text 'Content blocks: {block_count}' not found for project '{proj_title}'")
            else:
                checks_passed.append(f"[C] Text 'Content blocks: {block_count}' found for project '{proj_title}'")
        
            # 5e. If has children, verify bulletedList with child page titles
            if child_pages:
                for child in child_pages:
                    child_title = child.get("title", "")
                    child_listed = False
                    for block in dashboard_blocks_sorted:
                        if block.get("type") == "bulletedList":
                            content = block.get("content", "")
                            if child_title.lower() in content.lower():
                                child_listed = True
                                break
                
                    if not child_listed:
                        errors.append(f"[X] Child page '{child_title}' not listed in bulletedList for project '{proj_title}'")
                    else:
                        checks_passed.append(f"[C] Child page '{child_title}' listed in bulletedList for project '{proj_title}'")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

    # -----------------------------------------------------------------------------
    # Task: project-roadmap-summary
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_project_roadmap_summary(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate Project Roadmap Summary page creation and content.
    
    Goal: Create a summary page under Project Roadmap that analyzes to-do completion
    statistics from all quarter sub-pages.
    
    Validation steps:
    1. Find 'Project Roadmap' page
    2. Verify 'Project Roadmap Summary' page exists as child of 'Project Roadmap'
    3. Get all quarter sub-pages under 'Project Roadmap' (Q1 Goals, Q2 Goals)
    4. Count to-do blocks in each quarter page
    5. Verify heading_1 '📊 Quarterly Progress Overview' exists
    6. Verify heading_2 '📈 Completion Statistics' exists
    7. Verify paragraph with 'Total objectives across all quarters: [NUMBER]'
    8. For each quarter, verify heading_3 '🗓️ [Quarter Title]'
    9. Verify bulleted list with completion statistics for each quarter
    
    Weights: All checks must pass (binary 0/1).
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    
    # 1. Find 'Project Roadmap' page
    try:
        project_roadmap = _find_page_by_title(final_state_backend, "Project Roadmap")
        if not project_roadmap:
            errors.append("[X] Project Roadmap page not found")
        else:
            checks_passed.append("[C] Project Roadmap page found")
    
        project_roadmap_id = project_roadmap.get("_id")
    
        # 2. Verify 'Project Roadmap Summary' page exists as child of 'Project Roadmap'
        summary_page = _find_page_by_title_pattern_and_parent(final_state_backend, "Project Roadmap Summary", project_roadmap_id)
        if not summary_page:
            errors.append("[X] 'Project Roadmap Summary' page not found as child of 'Project Roadmap'")
        else:
            checks_passed.append("[C] 'Project Roadmap Summary' page found as child of 'Project Roadmap'")

        summary_page_id = summary_page.get("_id")

        # 3. Get all quarter sub-pages under 'Project Roadmap' (excluding the summary page)
        all_roadmap_children = _get_child_pages(final_state_backend, project_roadmap_id)
        quarter_pages = [p for p in all_roadmap_children if p.get("_id") != summary_page_id]

        if len(quarter_pages) == 0:
            errors.append("[X] No quarter pages found under 'Project Roadmap'")
        else:
            checks_passed.append("[C] quarter pages found under 'Project Roadmap'")

        # 4. Count to-do blocks in each quarter page
        quarter_stats = {}
        total_todos = 0

        for quarter_page in quarter_pages:
            quarter_id = quarter_page.get("_id")
            quarter_title = quarter_page.get("title", "")
            quarter_blocks = _get_blocks_for_page(final_state_backend, quarter_id)
        
            quarter_todos = [b for b in quarter_blocks if b.get("type") == "todo"]
            checked_count = len([b for b in quarter_todos if b.get("properties", {}).get("checked")])
            unchecked_count = len(quarter_todos) - checked_count
        
            total_count = len(quarter_todos)
            percentage = round((checked_count / total_count * 100) if total_count > 0 else 0)
        
            quarter_stats[quarter_title] = {
                "completed": checked_count,
                "pending": unchecked_count,
                "total": total_count,
                "percentage": percentage
            }
            total_todos += total_count
    
        # 5. Get blocks from summary page
        summary_blocks = _get_blocks_for_page(final_state_backend, summary_page_id)
        summary_blocks_sorted = sorted(summary_blocks, key=lambda b: b.get("order", 0))
    
        if len(summary_blocks_sorted) < 5:
            errors.append(f"[X] Summary page has too few blocks ({len(summary_blocks_sorted)})")
        else:
            checks_passed.append(f"[C] Summary page has too few blocks ({len(summary_blocks_sorted)})")
    
        # 6. Verify heading_1 '📊 Quarterly Progress Overview'
        heading1_found = False
        for block in summary_blocks_sorted:
            if block.get("type") == "heading1":
                content = block.get("content", "").lower()
                if "quarterly progress overview" in content:
                    heading1_found = True
                    break
    
        if not heading1_found:
            errors.append("[X] heading_1 '📊 Quarterly Progress Overview' not found")
        else:
            checks_passed.append("[C] heading_1 '📊 Quarterly Progress Overview' found")
    
        # 7. Verify heading_2 '📈 Completion Statistics'
        heading2_found = False
        for block in summary_blocks_sorted:
            if block.get("type") == "heading2":
                content = block.get("content", "").lower()
                if "completion statistics" in content:
                    heading2_found = True
                    break
    
        if not heading2_found:
            errors.append("[X] heading_2 '📈 Completion Statistics' not found")
        else:
            checks_passed.append("[C] heading_2 '📈 Completion Statistics' found")
    
        # 8. Verify paragraph with total count
        total_paragraph_found = False
        for block in summary_blocks_sorted:
            if block.get("type") == "paragraph":
                content = block.get("content", "").lower()
                # Check for "total objectives across all quarters: X" where X is the correct number
                if "total objectives across all quarters" in content and str(total_todos) in content:
                    total_paragraph_found = True
                    break
    
        if not total_paragraph_found:
            errors.append(f"[X] Paragraph with 'Total objectives across all quarters: {total_todos}' not found")
        else:
            checks_passed.append(f"[C] Paragraph with 'Total objectives across all quarters: {total_todos}' found")
    
        # 9. Verify each quarter has heading_3 and bulleted list with stats
        for quarter_title, stats in quarter_stats.items():
            # Check for heading_3 with quarter title
            quarter_heading_found = False
            for block in summary_blocks_sorted:
                if block.get("type") == "heading3":
                    content = block.get("content", "").lower()
                    if quarter_title.lower() in content:
                        quarter_heading_found = True
                        break
        
            if not quarter_heading_found:
                errors.append(f"[X] heading_3 '🗓️ {quarter_title}' not found")
            else:
                checks_passed.append(f"[C] heading_3 '🗓️ {quarter_title}' found")
        
            # Check for bulleted list items with completion stats
            completed_found = False
            pending_found = False
            rate_found = False
        
            for block in summary_blocks_sorted:
                if block.get("type") in ["bulletedList", "bulleted_list"]:
                    content = block.get("content", "").lower()
                
                    # Check completed count
                    if "completed" in content and str(stats["completed"]) in content:
                        completed_found = True
                
                    # Check pending count
                    if "pending" in content and str(stats["pending"]) in content:
                        pending_found = True
                
                    # Check completion rate
                    if "completion rate" in content and f"{stats['percentage']}%" in content:
                        rate_found = True
        
            if not completed_found:
                errors.append(f"[X] Bulleted item 'Completed: {stats['completed']} objectives' not found for {quarter_title}")
            else:
                checks_passed.append(f"[C] Bulleted item 'Completed: {stats['completed']} objectives' found for {quarter_title}")
        
            if not pending_found:
                errors.append(f"[X] Bulleted item 'Pending: {stats['pending']} objectives' not found for {quarter_title}")
            else:
                checks_passed.append(f"[C] Bulleted item 'Pending: {stats['pending']} objectives' found for {quarter_title}")
        
            if not rate_found:
                errors.append(f"[X] Bulleted item 'Completion rate: {stats['percentage']}%' not found for {quarter_title}")
            else:
                checks_passed.append(f"[C] Bulleted item 'Completion rate: {stats['percentage']}%' found for {quarter_title}")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_agent_code_examples_advanced_python_patterns(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate advanced Python patterns insertion on Code Examples Repository page.
    
    Goal: Insert advanced Python singleton pattern content AFTER 'Common python pattern for production code.'
          paragraph but BEFORE the 'Typescript Examples' heading2.
    
    Validation steps:
    1. Find the 'Code Examples Repository' page (page-20)
    2. Get all blocks for this page sorted by order
    3. Find the paragraph 'Common python pattern for production code.' and 'Typescript Examples' heading2
    4. Verify new content appears between them:
       - heading3 with '🐍 Advanced Python Patterns'
       - code block with language='python' containing the Singleton metaclass code
       - paragraph with 'Metaclass-based singleton implementation for thread-safe instance creation.'
       - divider block
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    
    # 1. Find the Code Examples Repository page
    try:
        code_examples_page = _find_page_by_title(final_state_backend, "Code Examples Repository")
        if not code_examples_page:
            errors.append("[X] Code Examples Repository page not found")
        else:
            checks_passed.append("[C] Code Examples Repository page found")
    
        page_id = code_examples_page.get("_id")
    
        # 2. Get all blocks for this page sorted by order
        all_blocks = final_state_backend.query({
            "collection": "blocks",
            "filter": {"pageId": page_id}
        })
        page_blocks = [b for b in all_blocks if b.get("pageId") == page_id]
        page_blocks_sorted = sorted(page_blocks, key=lambda b: b.get("order", 0))
    
        if not page_blocks_sorted:
            errors.append("[X] No blocks found on the page")
        else:
            checks_passed.append("[C] blocks found on the page")
    
        # 3. Find the anchor blocks
        # Find paragraph 'Common python pattern for production code.'
        python_pattern_paragraph = None
        for b in page_blocks_sorted:
            if b.get("type") == "paragraph" and "Common python pattern for production code" in b.get("content", ""):
                python_pattern_paragraph = b
                break
    
        if not python_pattern_paragraph:
            errors.append("[X] Paragraph 'Common python pattern for production code.' not found")
        else:
            checks_passed.append("[C] Paragraph 'Common python pattern for production code.' found")
    
        python_paragraph_order = python_pattern_paragraph.get("order", 0)
    
        # Find 'Typescript Examples' heading2
        typescript_heading = None
        for b in page_blocks_sorted:
            if b.get("type") in ["heading2", "heading_2"] and "Typescript Examples" in b.get("content", ""):
                if b.get("order", 0) > python_paragraph_order:
                    typescript_heading = b
                    break
    
        if not typescript_heading:
            errors.append("[X] heading2 'Typescript Examples' not found after Python pattern paragraph")
        else:
            checks_passed.append("[C] heading2 'Typescript Examples' found after Python pattern paragraph")
    
        typescript_heading_order = typescript_heading.get("order", 0)
    
        # 4. Find blocks inserted between the paragraph and Typescript heading
        inserted_blocks = [
            b for b in page_blocks_sorted 
            if b.get("order", 0) > python_paragraph_order and b.get("order", 0) < typescript_heading_order
        ]
    
        if not inserted_blocks:
            errors.append(f"[X] No blocks found between Python pattern paragraph (order {python_paragraph_order}) and Typescript heading (order {typescript_heading_order})")
        else:
            checks_passed.append(f"[C] blocks found between Python pattern paragraph (order {python_paragraph_order}) and Typescript heading (order {typescript_heading_order})")
    
        # 5. Validate heading3 with '🐍 Advanced Python Patterns'
        heading_block = next(
            (b for b in inserted_blocks if b.get("type") in ["heading3", "heading_3"]), 
            None
        )
        if not heading_block:
            errors.append("[X] heading3 block not found in inserted content")
        else:
            checks_passed.append("[C] heading3 block found in inserted content")
    
        heading_content = heading_block.get("content", "")
        if "Advanced Python Patterns" not in heading_content:
            errors.append(f"[X] heading3 missing 'Advanced Python Patterns' text. Found: '{heading_content}'")
        else:
            checks_passed.append(f"[C] heading3 has 'Advanced Python Patterns' text. Found: '{heading_content}'")
    
        if "🐍" not in heading_content:
            errors.append(f"[X] heading3 missing '🐍' emoji. Found: '{heading_content}'")
        else:
            checks_passed.append(f"[C] heading3 has '🐍' emoji. Found: '{heading_content}'")
    
        heading_order = heading_block.get("order", 0)
    
        # 6. Validate code block with language='python' and Singleton content
        code_blocks = [b for b in inserted_blocks if b.get("type") == "code"]
    
        if not code_blocks:
            errors.append("[X] Code block not found in inserted content")
        else:
            checks_passed.append("[C] Code block found in inserted content")
    
        # Find the code block with Singleton pattern
        singleton_code_block = None
        for code_block in code_blocks:
            content = code_block.get("content", "")
            if "class Singleton" in content and "_instances" in content and "__call__" in content:
                singleton_code_block = code_block
                break
    
        if not singleton_code_block:
            errors.append("[X] Code block with Singleton metaclass pattern not found")
        else:
            checks_passed.append("[C] Code block with Singleton metaclass pattern found")
    
        # Validate language property is set to 'python'
        properties = singleton_code_block.get("properties", {})
        language = properties.get("language", "")
        if language.lower() != "python":
            errors.append(f"[X] Code block language should be 'python', found: '{language}'")
        else:
            checks_passed.append(f"[C] Code block language should be 'python', found: '{language}'")
    
        # Validate code content contains key elements
        code_content = singleton_code_block.get("content", "")
        required_code_elements = [
            "class Singleton(type)",
            "_instances = {}",
            "def __call__(cls",
            "cls._instances[cls] = super().__call__",
            "return cls._instances[cls]"
        ]
    
        for element in required_code_elements:
            if element not in code_content:
                errors.append(f"[X] Code block missing required element: '{element}'")
            else:
                checks_passed.append(f"[C] Code block has required element: '{element}'")
    
        code_order = singleton_code_block.get("order", 0)
    
        # 7. Validate paragraph with 'Metaclass-based singleton implementation...'
        description_paragraph = None
        for b in inserted_blocks:
            if b.get("type") == "paragraph":
                content = b.get("content", "")
                if "Metaclass-based singleton implementation" in content and "thread-safe" in content:
                    description_paragraph = b
                    break
    
        if not description_paragraph:
            errors.append("[X] Paragraph with 'Metaclass-based singleton implementation for thread-safe instance creation.' not found")
        else:
            checks_passed.append("[C] Paragraph with 'Metaclass-based singleton implementation for thread-safe instance creation.' found")
    
        paragraph_order = description_paragraph.get("order", 0)
    
        # 8. Validate divider block exists
        divider_block = next(
            (b for b in inserted_blocks if b.get("type") == "divider"), 
            None
        )
    
        if not divider_block:
            errors.append("[X] Divider block not found in inserted content")
        else:
            checks_passed.append("[C] Divider block found in inserted content")
    
        divider_order = divider_block.get("order", 0)
    
        # 9. Verify order: heading3 -> code block -> paragraph -> divider
        if not (heading_order < code_order):
            errors.append(f"[X] Heading3 (order {heading_order}) should appear before code block (order {code_order})")
        else:
            checks_passed.append(f"[C] Heading3 (order {heading_order}) should appear before code block (order {code_order})")
    
        if not (code_order < paragraph_order):
            errors.append(f"[X] Code block (order {code_order}) should appear before description paragraph (order {paragraph_order})")
        else:
            checks_passed.append(f"[C] Code block (order {code_order}) should appear before description paragraph (order {paragraph_order})")
    
        if not (paragraph_order < divider_order):
            errors.append(f"[X] Description paragraph (order {paragraph_order}) should appear before divider (order {divider_order})")
        else:
            checks_passed.append(f"[C] Description paragraph (order {paragraph_order}) should appear before divider (order {divider_order})")
    
        # All validations passed
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_agent_onboarding_checklist_generation(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate onboarding checklist generation task.
    
    Goal: Navigate to Onboarding Guide, count numbered list items, add a summary callout
    after First Week Goals heading, and create a checklist section at the end with 
    emoji-prefixed todos.
    
    Validation steps:
    1. Find 'Onboarding Guide' page
    2. Get all blocks for that page
    3. Verify callout block exists with blue_background, '📋' icon, and correct text
       'Total onboarding tasks: 6 | Estimated time: 12 hours'
    4. Verify callout is positioned after 'First Week Goals' heading
    5. Verify heading_2 '✅ Onboarding Checklist' exists at the end
    6. Verify 6 todo blocks exist after the checklist heading with correct emoji prefixes:
       - 💻 Set up your workstation and accounts
       - 👥 Meet with your team lead
       - 📖 Read through the company handbook
       - 📖 Complete all required training modules
       - 👥 Schedule 1:1 meetings with teammates
       - 💻 Set up your development environment
    
    Weights: All checks must pass (binary 0/1).
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    
    # 1. Find 'Onboarding Guide' page
    try:
        onboarding_guide = _find_page_by_title(final_state_backend, "Onboarding Guide")
        if not onboarding_guide:
            errors.append("[X] 'Onboarding Guide' page not found")
        else:
            checks_passed.append("[C] 'Onboarding Guide' page found")
    
        onboarding_guide_id = onboarding_guide.get("_id")
    
        # 2. Get all blocks for the page
        page_blocks = _get_blocks_for_page(final_state_backend, onboarding_guide_id)
        if not page_blocks:
            errors.append("[X] No blocks found in 'Onboarding Guide' page")
        else:
            checks_passed.append("[C] blocks found in 'Onboarding Guide' page")
    
        # Sort blocks by order
        page_blocks_sorted = sorted(page_blocks, key=lambda b: b.get("order", 0))
    
        # 3. Find 'First Week Goals' heading
        first_week_goals_idx = None
        for idx, block in enumerate(page_blocks_sorted):
            if block.get("type") == "heading2":
                content = block.get("content", "").lower()
                if "first week goals" in content:
                    first_week_goals_idx = idx
                    break
    
        if first_week_goals_idx is None:
            errors.append("[X] heading_2 'First Week Goals' not found")
        else:
            checks_passed.append("[C] heading_2 'First Week Goals' found")
    
        # 4. Verify callout block exists with correct properties after First Week Goals heading
        callout_found = False
        callout_idx = None
    
        for idx, block in enumerate(page_blocks_sorted):
            if block.get("type") == "callout":
                props = block.get("properties", {})
                bg_color = props.get("backgroundColor", "")
                icon = props.get("icon", "")
                content = block.get("content", "")
            
                # Check blue background
                if "blue" not in bg_color.lower():
                    continue
            
                # Check icon contains 📋
                if "📋" not in icon:
                    continue
            
                # Check content contains the expected text
                content_lower = content.lower()
                if "total onboarding tasks: 6" in content_lower and "estimated time: 12 hours" in content_lower:
                    callout_found = True
                    callout_idx = idx
                    break
    
        if not callout_found:
            errors.append("[X] Callout with blue_background, '📋' icon, and 'Total onboarding tasks: 6 | Estimated time: 12 hours' not found")
        else:
            checks_passed.append("[C] Callout with blue_background, '📋' icon, and 'Total onboarding tasks: 6 | Estimated time: 12 hours' found")
    
        # 5. Verify callout is positioned after First Week Goals heading
        if callout_idx <= first_week_goals_idx:
            errors.append("[X] Callout must be positioned after 'First Week Goals' heading")
        else:
            checks_passed.append("[C] Callout must be positioned after 'First Week Goals' heading")
    
        # 6. Find heading_2 '✅ Onboarding Checklist' at the end
        checklist_heading_idx = None
        for idx, block in enumerate(page_blocks_sorted):
            if block.get("type") == "heading2":
                content = block.get("content", "")
                if "onboarding checklist" in content.lower():
                    checklist_heading_idx = idx
                    break
    
        if checklist_heading_idx is None:
            errors.append("[X] heading_2 '✅ Onboarding Checklist' not found")
        else:
            checks_passed.append("[C] heading_2 '✅ Onboarding Checklist' found")
    
        # 7. Verify the checklist heading is after First Week Goals section (at the end)
        if checklist_heading_idx <= first_week_goals_idx:
            errors.append("[X] '✅ Onboarding Checklist' heading must be at the end of the page")
        else:
            checks_passed.append("[C] '✅ Onboarding Checklist' heading must be at the end of the page")
    
        # 8. Verify 6 todo blocks exist after the checklist heading with correct emoji prefixes
        expected_todos = [
            ("💻", "set up your workstation and accounts"),
            ("👥", "meet with your team lead"),
            ("📖", "read through the company handbook"),
            ("📖", "complete all required training modules"),
            ("👥", "schedule 1:1 meetings with teammates"),
            ("💻", "set up your development environment"),
        ]
    
        # Get todo blocks after checklist heading
        todo_blocks = []
        for idx in range(checklist_heading_idx + 1, len(page_blocks_sorted)):
            block = page_blocks_sorted[idx]
            if block.get("type") == "todo":
                todo_blocks.append(block)
            # Stop if we hit another heading (but we don't expect one at the end)
            elif block.get("type") in ["heading1", "heading2", "heading3"]:
                break
    
        if len(todo_blocks) < 6:
            errors.append(f"[X] Expected 6 todo blocks after '✅ Onboarding Checklist' heading, found {len(todo_blocks)}")
        else:
            checks_passed.append(f"[C] Found 6 todo blocks after '✅ Onboarding Checklist' heading as expected")
    
        # Verify each expected todo is present with correct emoji prefix
        found_todos = []
        for expected_emoji, expected_text in expected_todos:
            for block in todo_blocks:
                content = block.get("content", "")
                content_lower = content.lower()
            
                # Check if content contains expected text and emoji
                if expected_text in content_lower and expected_emoji in content:
                    found_todos.append((expected_emoji, expected_text))
                    break
    
        if len(found_todos) < 6:
            missing = [(e, t) for e, t in expected_todos if (e, t) not in found_todos]
            missing_str = ", ".join([f"'{e} {t}'" for e, t in missing])
            errors.append(f"[X] Missing todo blocks with correct emoji prefixes: {missing_str}")
        else:
            checks_passed.append(f"[C] has todo blocks with correct emoji prefixes: {missing_str}")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

    # -----------------------------------------------------------------------------
    # Task: company-handbook-toc
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_company_handbook_toc(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate table of contents creation for Company Handbook page.
    
    Goal: Create a detailed table of contents at the beginning of the Company Handbook
    page with hierarchical formatting based on heading levels.
    
    Validation steps:
    1. Find Company Handbook page (page-16)
    2. Verify heading_2 '📑 Table of Contents' is the first block (order 0)
    3. Verify bulleted list items follow with correct formatting:
       - heading1: '• [text] ↗'
       - heading2: ' ◦ [text] ↗'
       - heading3: '  ▪ [text] ↗'
    4. Verify divider exists after TOC items
    5. Verify callout with gray_background, icon '🔍', search tip text
    
    Weights: All checks must pass (binary 0/1).
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    
    # 1. Find 'Company Handbook' page
    try:
        company_handbook = _find_page_by_title(final_state_backend, "Company Handbook")
        if not company_handbook:
            errors.append("[X] Company Handbook page not found")
        else:
            checks_passed.append("[C] Company Handbook page found")
    
        page_id = company_handbook.get("_id")
        page_blocks = _get_blocks_for_page(final_state_backend, page_id)
    
        if not page_blocks:
            errors.append("[X] No blocks found on Company Handbook page")
        else:
            checks_passed.append("[C] blocks found on Company Handbook page")
    
        # Sort blocks by order
        page_blocks_sorted = sorted(page_blocks, key=lambda b: b.get("order", 0))
    
        # 2. Verify heading_2 '📑 Table of Contents' is the first block
        first_block = page_blocks_sorted[0] if page_blocks_sorted else None
    
        if not first_block:
            errors.append("[X] No blocks found on the page")
        else:
            checks_passed.append("[C] blocks found on the page")
    
        if first_block.get("type") != "heading2":
            errors.append(f"[X] First block should be heading2, found '{first_block.get('type')}'")
        else:
            checks_passed.append(f"[C] First block should be heading2, found '{first_block.get('type')}'")
    
        first_block_content = first_block.get("content", "")
        if "📑" not in first_block_content or "table of contents" not in first_block_content.lower():
            errors.append(f"[X] First block should be '📑 Table of Contents', found '{first_block_content}'")
        else:
            checks_passed.append(f"[C] First block should be '📑 Table of Contents', found '{first_block_content}'")
    
        # 3. Find all heading blocks that existed before the TOC was added
        # These are headings that are NOT the TOC heading itself
        original_headings = []
        for block in page_blocks_sorted:
            block_type = block.get("type", "")
            content = block.get("content", "")
        
            if block_type in ["heading1", "heading2", "heading3"]:
                # Skip the TOC heading itself
                if "table of contents" in content.lower():
                    continue
                original_headings.append({
                    "type": block_type,
                    "content": content
                })
    
        if not original_headings:
            errors.append("[X] No original heading blocks found on the page")
        else:
            checks_passed.append("[C] original heading blocks found on the page")
    
        # 4. Find bulleted list items after the TOC heading
        toc_heading_idx = 0  # First block is the TOC heading
        bulleted_items = []
        divider_found = False
        divider_idx = None
    
        for idx in range(toc_heading_idx + 1, len(page_blocks_sorted)):
            block = page_blocks_sorted[idx]
            block_type = block.get("type", "")
        
            if block_type == "bulletedList":
                bulleted_items.append(block)
            elif block_type == "divider":
                divider_found = True
                divider_idx = idx
                break
            elif block_type in ["heading1", "heading2", "heading3"]:
                # If we hit a heading block, stop collecting TOC items
                break
    
        if len(bulleted_items) == 0:
            errors.append("[X] No bulleted list items found for table of contents")
        else:
            checks_passed.append("[C] bulleted list items found for table of contents")
    
        # 5. Verify bulleted list items match heading count and have correct format
        # Each item should end with ↗ and use correct bullet prefix
        items_with_arrow = 0
        for item in bulleted_items:
            content = item.get("content", "")
            if "↗" in content:
                items_with_arrow += 1
    
        if items_with_arrow < len(original_headings):
            errors.append(f"[X] Expected {len(original_headings)} TOC items with ↗, found {items_with_arrow}")
        else:
            checks_passed.append(f"[C] Expected {len(original_headings)} TOC items with ↗, found {items_with_arrow}")
    
        # 6. Verify correct bullet prefixes based on heading level
        # heading1: '• '
        # heading2: ' ◦ ' or '◦'
        # heading3: '  ▪ ' or '▪'
        expected_toc_items = []
        for heading in original_headings:
            h_type = heading["type"]
            h_content = heading["content"]
        
            if h_type == "heading1":
                expected_toc_items.append(("•", h_content))
            elif h_type == "heading2":
                expected_toc_items.append(("◦", h_content))
            elif h_type == "heading3":
                expected_toc_items.append(("▪", h_content))
    
        # Verify TOC items contain expected content and markers
        matched_items = 0
        for expected_marker, expected_text in expected_toc_items:
            for item in bulleted_items:
                item_content = item.get("content", "")
                # Check if the expected text is in the item (case-insensitive)
                if expected_text.lower() in item_content.lower():
                    # Check if the correct marker is present
                    if expected_marker in item_content:
                        matched_items += 1
                        break
    
        if matched_items < len(expected_toc_items):
            errors.append(f"[X] TOC items missing correct bullet markers. Expected {len(expected_toc_items)}, found {matched_items} with correct format")
        else:
            checks_passed.append(f"[C] TOC items has correct bullet markers. Expected {len(expected_toc_items)}, found {matched_items} with correct format")
    
        # 7. Verify divider exists after TOC
        if not divider_found:
            errors.append("[X] Divider not found after table of contents")
        else:
            checks_passed.append("[C] Divider found after table of contents")
    
        # 8. Verify callout with gray_background, icon '🔍', search tip text after divider
        callout_found = False
        callout_valid = False
    
        for idx in range(divider_idx + 1 if divider_idx else 0, len(page_blocks_sorted)):
            block = page_blocks_sorted[idx]
            if block.get("type") == "callout":
                callout_found = True
                props = block.get("properties", {})
                content = block.get("content", "").lower()
                bg_color = props.get("backgroundColor", "")
                icon = props.get("icon", "")
            
                # Check gray background
                if "gray" not in bg_color.lower():
                    errors.append(f"[X] Callout should have gray_background, found '{bg_color}'")
                else:
                    checks_passed.append(f"[C] Callout should have gray_background, found '{bg_color}'")
            
                # Check icon
                if "🔍" not in icon:
                    errors.append(f"[X] Callout should have '🔍' icon, found '{icon}'")
                else:
                    checks_passed.append(f"[C] Callout should have '🔍' icon, found '{icon}'")
            
                # Check content contains search tip
                if "ctrl+f" in content or "cmd+f" in content or "search" in content:
                    callout_valid = True
                    break
    
        if not callout_found:
            errors.append("[X] Callout not found after divider")
        else:
            checks_passed.append("[C] Callout found after divider")
    
        if not callout_valid:
            errors.append("[X] Callout does not contain search tip text (Ctrl+F/Cmd+F)")
        else:
            checks_passed.append("[C] Callout does contains search tip text (Ctrl+F/Cmd+F)")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

    # -----------------------------------------------------------------------------
    # Task: favorite-pages-directory
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_favorite_pages_directory(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Favorite Pages Directory creation.
    
    Goal: Find all favorite pages and create a directory page listing them grouped by workspace.
    
    Validation steps (ordered):
    1. Find 'Favorite Pages Directory' page at root level (no parentId) with '⭐' icon
    2. Verify heading_1 '⭐ Favorite Pages Overview'
    3. Verify heading_2 '📊 Statistics' followed by paragraph with correct count
    4. Verify heading_2 '📑 Favorites by Workspace'
    5. For each workspace with favorites, verify heading_3 'Workspace: [ID]'
    6. Verify bulletedList items with format '[ICON] [TITLE] - Last updated: [DATE]'
    7. Verify yellow callout with 💫 icon and tip text at end
    
    Weights: All-or-nothing (1.0 if all pass, 0.0 otherwise)
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    
    # 1. Find 'Favorite Pages Directory' at root level with ⭐ icon
    try:
        directory_pages_result = final_state_backend.query({
            "collection": "pages",
            "filter": {
                "title": {"$regex": "Favorite Pages Directory", "$options": "i"},
                "parentId": None
            }
        })
        directory_candidates = directory_pages_result if isinstance(directory_pages_result, list) else []
        directory_page = None
        for page in directory_candidates:
            icon = page.get("icon", "")
            if icon == "⭐":
                directory_page = page
                break
            else:
                errors.append(f"[X] 'Favorite Pages Directory' found but icon is '{icon}', expected '⭐'")

        if not directory_page:
            errors.append("[X] 'Favorite Pages Directory' not found at root level with '⭐' icon")
        else:
            checks_passed.append("[C] 'Favorite Pages Directory' found at root level with '⭐' icon")

        directory_page_id = directory_page.get("_id")

        # Get all blocks for the directory page
        directory_blocks = _get_blocks_for_page(final_state_backend, directory_page_id)
        if not directory_blocks:
            errors.append("[X] Directory page has no blocks")
        else:
            checks_passed.append("[C] Directory page has blocks")

        # Sort blocks by order
        directory_blocks_sorted = sorted(directory_blocks, key=lambda b: b.get("order", 0))

        # Count all favorite pages in backend
        favorite_pages_result = final_state_backend.query({
            "collection": "pages",
            "filter": {"isFavorite": True}
        })
        favorite_pages = favorite_pages_result if isinstance(favorite_pages_result, list) else []
        expected_count = len(favorite_pages)
    
        if expected_count == 0:
            errors.append("[X] No favorite pages found in backend to analyze")
        else:
            checks_passed.append("[C] favorite pages found in backend to analyze")
    
        # Group favorite pages by workspaceId
        favorites_by_workspace: Dict[str, List[Dict[str, Any]]] = {}
        for page in favorite_pages:
            workspace_id = page.get("workspaceId", "unknown")
            if workspace_id not in favorites_by_workspace:
                favorites_by_workspace[workspace_id] = []
            favorites_by_workspace[workspace_id].append(page)
    
        # 2. Verify heading_1 '⭐ Favorite Pages Overview'
        h1_found = False
        for block in directory_blocks_sorted:
            if block.get("type") in ["heading1", "heading_1"]:
                content = block.get("content", "").lower()
                if "favorite pages overview" in content:
                    h1_found = True
                    break
    
        if not h1_found:
            errors.append("[X] heading_1 '⭐ Favorite Pages Overview' not found")
        else:
            checks_passed.append("[C] heading_1 '⭐ Favorite Pages Overview' found")
    
        # 3. Verify heading_2 '📊 Statistics' with correct count paragraph
        statistics_h2_found = False
        count_paragraph_found = False
    
        for i, block in enumerate(directory_blocks_sorted):
            if block.get("type") in ["heading2", "heading_2"]:
                content = block.get("content", "").lower()
                if "statistics" in content:
                    statistics_h2_found = True
                    # Look for count paragraph after this heading
                    for j in range(i + 1, min(i + 5, len(directory_blocks_sorted))):
                        next_block = directory_blocks_sorted[j]
                        if next_block.get("type") == "paragraph":
                            para_content = next_block.get("content", "").lower()
                            if "total favorite pages" in para_content and str(expected_count) in para_content:
                                count_paragraph_found = True
                                break
                        # Stop if we hit another heading
                        if next_block.get("type") in ["heading1", "heading_1", "heading2", "heading_2", "heading3", "heading_3"]:
                            break
                    break
    
        if not statistics_h2_found:
            errors.append("[X] heading_2 '📊 Statistics' not found")
        else:
            checks_passed.append("[C] heading_2 '📊 Statistics' found")
    
        if not count_paragraph_found:
            errors.append(f"[X] Paragraph 'Total favorite pages: {expected_count}' not found under Statistics section")
        else:
            checks_passed.append(f"[C] Paragraph 'Total favorite pages: {expected_count}' found under Statistics section")
    
        # 4. Verify heading_2 '📑 Favorites by Workspace'
        favorites_by_workspace_h2_found = False
        for block in directory_blocks_sorted:
            if block.get("type") in ["heading2", "heading_2"]:
                content = block.get("content", "").lower()
                if "favorites by workspace" in content:
                    favorites_by_workspace_h2_found = True
                    break
    
        if not favorites_by_workspace_h2_found:
            errors.append("[X] heading_2 '📑 Favorites by Workspace' not found")
        else:
            checks_passed.append("[C] heading_2 '📑 Favorites by Workspace' found")
    
        # 5. Verify heading_3 for each workspace with favorites
        for workspace_id in favorites_by_workspace.keys():
            workspace_h3_found = False
            for block in directory_blocks_sorted:
                if block.get("type") in ["heading3", "heading_3"]:
                    content = block.get("content", "").lower()
                    # Check if workspace ID is mentioned
                    if workspace_id.lower() in content and "workspace" in content:
                        workspace_h3_found = True
                        break
        
            if not workspace_h3_found:
                errors.append(f"[X] heading_3 'Workspace: {workspace_id}' not found")
            else:
                checks_passed.append(f"[C] heading_3 'Workspace: {workspace_id}' found")
    
        # 6. Verify bulletedList items exist with proper format (icon, title, date)
        bulleted_items = [b for b in directory_blocks_sorted if b.get("type") in ["bulletedList", "bulleted_list"]]
    
        if len(bulleted_items) < expected_count:
            errors.append(f"[X] Expected at least {expected_count} bulleted list items, found {len(bulleted_items)}")
        else:
            checks_passed.append(f"[C] Expected at least {expected_count} bulleted list items, found {len(bulleted_items)}")
    
        # Check that bulleted items contain expected page info (at least check format presence)
        items_with_date = 0
        for item in bulleted_items:
            content = item.get("content", "").lower()
            # Check for date format indicators
            if "last updated" in content or "updated" in content:
                items_with_date += 1
    
        if items_with_date < expected_count:
            errors.append(f"[X] Bulleted items should include 'Last updated: [DATE]' format, only {items_with_date} items have date info")
        else:
            checks_passed.append(f"[C] Bulleted items should include 'Last updated: [DATE]' format, only {items_with_date} items have date info")
    
        # 7. Verify yellow callout with 💫 icon and tip text at end
        callout_found = False
        for block in directory_blocks_sorted:
            if block.get("type") == "callout":
                properties = block.get("properties", {})
                background = properties.get("backgroundColor", properties.get("background", ""))
                icon = properties.get("icon", "")
                content = block.get("content", "").lower()
            
                # Check for yellow background
                is_yellow = "yellow" in background.lower() if background else False
                # Check for 💫 icon
                has_icon = "💫" in icon
                # Check for tip text
                has_tip_text = "mark frequently accessed pages as favorites" in content
            
                if is_yellow and has_icon and has_tip_text:
                    callout_found = True
                    break
                elif has_tip_text:
                    # Found the callout but maybe missing styling
                    if not is_yellow:
                        errors.append(f"[X] Callout found but background is '{background}', expected 'yellow_background'")
                    else:
                        checks_passed.append(f"[C] Callout found but background is '{background}', expected 'yellow_background'")
                    if not has_icon:
                        errors.append(f"[X] Callout found but icon is '{icon}', expected '💫'")
                    else:
                        checks_passed.append(f"[C] Callout found but icon is '{icon}', expected '💫'")
    
        if not callout_found:
            errors.append("[X] Yellow callout with 💫 icon and tip text not found")
        else:
            checks_passed.append("[C] Yellow callout with 💫 icon and tip text found")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

    # -----------------------------------------------------------------------------
    # Task: getting-started-onboarding-checklist
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_getting_started_onboarding_checklist(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate advanced onboarding checklist added to Getting Started page.
    
    Goal: Navigate to the 'Getting Started' page and insert a sophisticated 
    onboarding checklist AFTER the existing to-do items but BEFORE any other 
    content (specifically before the 'Key Features' heading).
    
    Validation steps (ordered):
    1. Find the Getting Started page (page-1)
    2. Get all blocks for the page and sort by order
    3. Find the last existing todo block (order 6: "Share a page with a teammate")
    4. Find the 'Key Features' heading2 block (order 7)
    5. Verify divider exists AFTER last existing todo but BEFORE Key Features
    6. Verify heading2 '🎯 Advanced Setup Checklist' exists after divider
    7. Verify callout with gray_background, no icon, and exact text
    8. Verify exactly six unchecked todo blocks with specific emojis and text in correct order
    
    Weights: All-or-nothing (1.0 if all pass, 0.0 otherwise)
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    
    # 1. Find the Getting Started page
    try:
        getting_started_page = _find_page_by_title(final_state_backend, "Getting Started")
        if not getting_started_page:
            errors.append("[X] Getting Started page not found")
        else:
            checks_passed.append("[C] Getting Started page found")
    
        page_id = getting_started_page.get("_id")
        page_blocks = _get_blocks_for_page(final_state_backend, page_id)
    
        if not page_blocks:
            errors.append("[X] No blocks found on Getting Started page")
        else:
            checks_passed.append("[C] blocks found on Getting Started page")
    
        # 2. Sort blocks by order
        page_blocks_sorted = sorted(page_blocks, key=lambda b: b.get("order", 0))
    
        # 3. Find key reference points in the original page structure
        # We need to find: last original todo, and the Key Features heading
        last_original_todo_idx = None
        key_features_heading_idx = None
    
        for idx, block in enumerate(page_blocks_sorted):
            content = block.get("content", "")
            content_lower = content.lower()
            block_type = block.get("type", "")
        
            # Track the last of the original 4 todos (Share a page with a teammate)
            if block_type == "todo" and "share a page with a teammate" in content_lower:
                last_original_todo_idx = idx
        
            # Find Key Features heading
            if block_type == "heading2" and "key features" in content_lower:
                key_features_heading_idx = idx
    
        if last_original_todo_idx is None:
            errors.append("[X] Original todo 'Share a page with a teammate' not found")
        else:
            checks_passed.append("[C] Original todo 'Share a page with a teammate' found")
    
        if key_features_heading_idx is None:
            errors.append("[X] heading2 'Key Features' not found")
        else:
            checks_passed.append("[C] heading2 'Key Features' found")
    
        # 4. Find divider AFTER last original todo
        divider_idx = None
        for idx in range(last_original_todo_idx + 1, len(page_blocks_sorted)):
            block = page_blocks_sorted[idx]
            if block.get("type") == "divider":
                divider_idx = idx
                break
            # Stop if we hit Key Features without finding a divider
            if idx >= key_features_heading_idx:
                break
    
        if divider_idx is None:
            errors.append("[X] Divider not found after existing todos")
        else:
            checks_passed.append("[C] Divider found after existing todos")
    
        if divider_idx <= last_original_todo_idx:
            errors.append(f"[X] Divider must appear AFTER existing todos (Divider at idx {divider_idx}, last todo at {last_original_todo_idx})")
        else:
            checks_passed.append(f"[C] Divider must appear AFTER existing todos (Divider at idx {divider_idx}, last todo at {last_original_todo_idx})")
    
        # 5. Find heading2 '🎯 Advanced Setup Checklist' after divider
        advanced_setup_heading_idx = None
        for idx in range(divider_idx + 1, len(page_blocks_sorted)):
            block = page_blocks_sorted[idx]
            content = block.get("content", "")
            block_type = block.get("type", "")
        
            if block_type == "heading2" and "🎯" in content and "advanced setup checklist" in content.lower():
                advanced_setup_heading_idx = idx
                break
    
        if advanced_setup_heading_idx is None:
            errors.append("[X] heading2 '🎯 Advanced Setup Checklist' not found after divider")
        else:
            checks_passed.append("[C] heading2 '🎯 Advanced Setup Checklist' found after divider")
    
        if advanced_setup_heading_idx <= divider_idx:
            errors.append(f"[X] Advanced Setup Checklist heading must be AFTER divider (Heading at idx {advanced_setup_heading_idx}, divider at {divider_idx})")
        else:
            checks_passed.append(f"[C] Advanced Setup Checklist heading must be AFTER divider (Heading at idx {advanced_setup_heading_idx}, divider at {divider_idx})")
    
        # 6. Find callout with gray_background, no icon, and exact text after heading
        gray_callout = None
        gray_callout_idx = None
        expected_callout_text = "The following steps are for power users who want to maximize their workspace efficiency"
    
        for idx in range(advanced_setup_heading_idx + 1, len(page_blocks_sorted)):
            block = page_blocks_sorted[idx]
            if block.get("type") == "callout":
                props = block.get("properties", {})
                bg_color = props.get("backgroundColor", "").lower()
                icon = props.get("icon", "")
                content = block.get("content", "")
            
                # Check for gray background and no icon
                if "gray" in bg_color:
                    # No icon means icon is empty, null, or absent
                    if not icon or icon == "":
                        gray_callout = block
                        gray_callout_idx = idx
                        break
    
        if gray_callout is None:
            errors.append("[X] Callout with gray_background and no icon not found after Advanced Setup Checklist heading")
        else:
            checks_passed.append("[C] Callout with gray_background and icon found after Advanced Setup Checklist heading")
    
        # Verify callout text
        callout_content = gray_callout.get("content", "")
        if expected_callout_text.lower() not in callout_content.lower():
            errors.append(f"[X] Callout text should be '{expected_callout_text}'. Got: '{callout_content}'")
        else:
            checks_passed.append(f"[C] Callout text should be '{expected_callout_text}'. Got: '{callout_content}'")
    
        # 7. Find exactly six unchecked todo blocks with specific emojis and text in correct order
        expected_todos = [
            "⚡ Configure keyboard shortcuts",
            "🔧 Set up browser extensions",
            "🔔 Customize notification preferences",
            "🎨 Create personal page templates",
            "📱 Install mobile app and sync",
            "🤖 Set up automation workflows"
        ]
    
        new_todos_found = []
        for idx in range(gray_callout_idx + 1, len(page_blocks_sorted)):
            block = page_blocks_sorted[idx]
            block_type = block.get("type", "")
        
            # Stop if we hit the Key Features section or other heading
            if block_type in ["heading2", "heading1"]:
                break
        
            if block_type == "todo":
                props = block.get("properties", {})
                content = block.get("content", "")
                checked = props.get("checked", False)
            
                # All new todos must be unchecked
                if checked:
                    errors.append(f"[X] Todo '{content}' should be unchecked")
                else:
                    checks_passed.append(f"[C] Todo '{content}' should be unchecked")
            
                new_todos_found.append(content)
    
        # Verify we have exactly 6 todos
        if len(new_todos_found) != 6:
            errors.append(f"[X] Expected exactly 6 new todo blocks, found {len(new_todos_found)}")
        else:
            checks_passed.append(f"[C] Expected exactly 6 new todo blocks, found {len(new_todos_found)}")
    
        # Verify each todo matches expected content in order
        for i, (expected, actual) in enumerate(zip(expected_todos, new_todos_found)):
            # Extract emoji and text from expected
            expected_emoji = expected.split()[0]
            expected_text = expected.split(maxsplit=1)[1].lower() if " " in expected else ""
        
            actual_lower = actual.lower()
        
            # Check emoji is present
            if expected_emoji not in actual:
                errors.append(f"[X] Todo {i+1} should contain emoji '{expected_emoji}'. Got: '{actual}'")
            else:
                checks_passed.append(f"[C] Todo {i+1} should contain emoji '{expected_emoji}'. Got: '{actual}'")
        
            # Check text content (case-insensitive)
            if expected_text not in actual_lower:
                errors.append(f"[X] Todo {i+1} should be '{expected}'. Got: '{actual}'")
            else:
                checks_passed.append(f"[C] Todo {i+1} should be '{expected}'. Got: '{actual}'")
    
        # 8. Verify all new content is BEFORE Key Features heading
        # Re-find Key Features heading in the current block list (it may have moved)
        new_key_features_idx = None
        for idx, block in enumerate(page_blocks_sorted):
            content = block.get("content", "")
            block_type = block.get("type", "")
            if block_type == "heading2" and "key features" in content.lower():
                new_key_features_idx = idx
                break
    
        if new_key_features_idx is not None:
            # Find the last new todo's index
            last_new_todo_idx = gray_callout_idx + len(new_todos_found)
            if last_new_todo_idx >= new_key_features_idx:
                errors.append("[X] New content must appear BEFORE 'Key Features' heading")
            else:
                checks_passed.append("[C] New content must appear BEFORE 'Key Features' heading")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

    # -----------------------------------------------------------------------------
    # Task: engineering-wiki-index
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_engineering_wiki_index(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate comprehensive Engineering Wiki Index page creation.
    
    Goal: Create an index page under Engineering Wiki that documents all architecture 
    pages and their sub-pages with a coverage report.
    
    Validation steps:
    1. Verify 'Engineering Wiki Index' page exists as child of 'Engineering Wiki'
    2. Verify heading1 '📚 Engineering Wiki Index' exists
    3. Verify heading2 '🏗️ Architecture Documentation' exists
    4. For each page with 'Architecture' in title:
       - Verify heading3 with '[icon] [title]' format exists
       - Verify numbered list of child pages under each heading3
    5. Verify divider block exists after architecture sections
    6. Verify heading2 '📊 Documentation Coverage Report' exists
    7. Verify bulleted list with total pages, pages with sub-pages, deepest nesting
    8. Verify callout with blue_background, '💡' icon, 'Use Cmd+K to quickly search for any documentation'
    
    Weights: All checks must pass (binary 0/1).
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    
    # 1. Find 'Engineering Wiki' page
    try:
        engineering_wiki = _find_page_by_title(final_state_backend, "Engineering Wiki")
        if not engineering_wiki:
            errors.append("[X] Engineering Wiki page not found")
        else:
            checks_passed.append("[C] Engineering Wiki page found")
    
        engineering_wiki_id = engineering_wiki.get("_id")
    
        # 2. Find 'Engineering Wiki Index' page as child of Engineering Wiki
        wiki_index = _find_page_by_title_pattern_and_parent(final_state_backend, "Engineering Wiki Index", engineering_wiki_id)
        if not wiki_index:
            errors.append("[X] 'Engineering Wiki Index' page not found as child of 'Engineering Wiki'")
        else:
            checks_passed.append("[C] 'Engineering Wiki Index' page found as child of 'Engineering Wiki'")

        wiki_index_id = wiki_index.get("_id")

        # 3. Get blocks from Engineering Wiki Index page
        index_blocks = _get_blocks_for_page(final_state_backend, wiki_index_id)

        if not index_blocks:
            errors.append("[X] Engineering Wiki Index page has no content blocks")
        else:
            checks_passed.append("[C] Engineering Wiki Index page has content blocks")

        # Sort blocks by order
        index_blocks_sorted = sorted(index_blocks, key=lambda b: b.get("order", 0))

        # 4. Find all pages containing 'Architecture' in title
        architecture_pages_result = final_state_backend.query({
            "collection": "pages",
            "filter": {"title": {"$regex": "architecture", "$options": "i"}}
        })
        architecture_pages = architecture_pages_result if isinstance(architecture_pages_result, list) else []
    
        if len(architecture_pages) == 0:
            errors.append("[X] No pages with 'Architecture' in title found")
        else:
            checks_passed.append("[C] pages with 'Architecture' in title found")
    
        # Expected architecture pages from initial data:
        # - Architecture (page-23, icon: 🏗️)
        # - Frontend Architecture (page-24, icon: 🎨)
        # - Backend Architecture (page-27, icon: ⚙️)
        expected_arch_count = 3
    
        if len(architecture_pages) < expected_arch_count:
            errors.append(f"[X] Expected at least {expected_arch_count} architecture pages, found {len(architecture_pages)}")
        else:
            checks_passed.append(f"[C] Expected at least {expected_arch_count} architecture pages, found {len(architecture_pages)}")
    
        # 5. Verify heading1 '📚 Engineering Wiki Index'
        heading1_found = False
        for block in index_blocks_sorted:
            if block.get("type") == "heading1":
                content = block.get("content", "").lower()
                if "engineering wiki index" in content:
                    heading1_found = True
                    break
    
        if not heading1_found:
            errors.append("[X] heading1 '📚 Engineering Wiki Index' not found")
        else:
            checks_passed.append("[C] heading1 '📚 Engineering Wiki Index' found")
    
        # 6. Verify heading2 '🏗️ Architecture Documentation'
        arch_heading_found = False
        for block in index_blocks_sorted:
            if block.get("type") == "heading2":
                content = block.get("content", "").lower()
                if "architecture documentation" in content:
                    arch_heading_found = True
                    break
    
        if not arch_heading_found:
            errors.append("[X] heading2 '🏗️ Architecture Documentation' not found")
        else:
            checks_passed.append("[C] heading2 '🏗️ Architecture Documentation' found")
    
        # 7. Verify heading3 blocks for each architecture page
        heading3_blocks = [b for b in index_blocks_sorted if b.get("type") == "heading3"]
    
        # Check that each architecture page has a heading3 entry
        arch_pages_listed = 0
        for arch_page in architecture_pages:
            arch_title = arch_page.get("title", "").lower()
            for h3 in heading3_blocks:
                h3_content = h3.get("content", "").lower()
                if arch_title in h3_content:
                    arch_pages_listed += 1
                    break
    
        if arch_pages_listed < len(architecture_pages):
            errors.append(f"[X] Only {arch_pages_listed}/{len(architecture_pages)} architecture pages have heading3 entries")
        else:
            checks_passed.append(f"[C] Only {arch_pages_listed}/{len(architecture_pages)} architecture pages have heading3 entries")
    
        # 8. Verify numbered list items exist for child pages
        # Count architecture pages that have children
        arch_pages_with_children = 0
        for arch_page in architecture_pages:
            arch_id = arch_page.get("_id")
            children = _get_child_pages(final_state_backend, arch_id)
            if len(children) > 0:
                arch_pages_with_children += 1
    
        # Check that numbered list blocks exist
        numbered_list_blocks = [b for b in index_blocks_sorted if b.get("type") == "numberedList"]
    
        # We expect numbered list items for child pages
        # Architecture has 2 children (Frontend Arch, Backend Arch)
        # Frontend Architecture has 2 children (Component Library, State Management)
        # Backend Architecture has 1 child (API Design Patterns)
        # Total child pages to list: 2 + 2 + 1 = 5
        expected_child_list_items = 5
    
        if len(numbered_list_blocks) < expected_child_list_items:
            errors.append(f"[X] Expected at least {expected_child_list_items} numbered list items for child pages, found {len(numbered_list_blocks)}")
        else:
            checks_passed.append(f"[C] Expected at least {expected_child_list_items} numbered list items for child pages, found {len(numbered_list_blocks)}")
    
        # 9. Verify divider exists
        divider_found = False
        for block in index_blocks_sorted:
            if block.get("type") == "divider":
                divider_found = True
                break
    
        if not divider_found:
            errors.append("[X] Divider block not found after architecture sections")
        else:
            checks_passed.append("[C] Divider block found after architecture sections")
    
        # 10. Verify heading2 '📊 Documentation Coverage Report'
        coverage_heading_found = False
        for block in index_blocks_sorted:
            if block.get("type") == "heading2":
                content = block.get("content", "").lower()
                if "documentation coverage report" in content:
                    coverage_heading_found = True
                    break
    
        if not coverage_heading_found:
            errors.append("[X] heading2 '📊 Documentation Coverage Report' not found")
        else:
            checks_passed.append("[C] heading2 '📊 Documentation Coverage Report' found")
    
        # 11. Verify bulleted list with statistics
        bulleted_list_blocks = [b for b in index_blocks_sorted if b.get("type") in ["bulletedList", "bulleted_list"]]
    
        # Check for the three required statistics
        stats_content = " ".join([b.get("content", "").lower() for b in bulleted_list_blocks])
    
        # Check for 'total architecture pages'
        if "total architecture pages" not in stats_content:
            errors.append("[X] Bulleted list missing 'Total architecture pages' statistic")
        else:
            checks_passed.append("[C] Bulleted list has 'Total architecture pages' statistic")
    
        # Check for 'pages with sub-pages'
        if "pages with sub-pages" not in stats_content:
            errors.append("[X] Bulleted list missing 'Pages with sub-pages' statistic")
        else:
            checks_passed.append("[C] Bulleted list has 'Pages with sub-pages' statistic")
    
        # Check for 'deepest nesting level'
        if "deepest nesting level" not in stats_content:
            errors.append("[X] Bulleted list missing 'Deepest nesting level' statistic")
        else:
            checks_passed.append("[C] Bulleted list has 'Deepest nesting level' statistic")
    
        # 12. Verify callout with blue_background, '💡' icon, and search hint
        callout_found = False
        for block in index_blocks_sorted:
            if block.get("type") == "callout":
                props = block.get("properties", {})
                bg_color = props.get("backgroundColor", "")
                icon = props.get("icon", "")
                content = block.get("content", "").lower()
            
                # Check blue background
                if "blue" not in bg_color.lower():
                    continue
            
                # Check icon
                if "💡" not in icon:
                    continue
            
                # Check content for search hint
                if "cmd+k" in content or "cmd + k" in content:
                    callout_found = True
                    break
    
        if not callout_found:
            errors.append("[X] Callout with blue_background, '💡' icon, and 'Use Cmd+K to quickly search' not found")
        else:
            checks_passed.append("[C] Callout with blue_background, '💡' icon, and 'Use Cmd+K to quickly search' found")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

    # -----------------------------------------------------------------------------
    # Task: engineering-wiki-content-insertion
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_engineering_wiki_content_insertion(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate content insertion and reorganization on the Engineering Wiki page.
    
    Goal: Add new sections, code blocks, and bookmarks to the Engineering Wiki page
    with precise positioning.
    
    Validation steps (ordered):
    1. Find the 'Engineering Wiki' page (page-4)
    2. Find Tech Stack heading and Development Setup heading to verify positioning
    3. Verify heading_2 '🔧 Development Standards' exists AFTER Tech Stack bullets and BEFORE Development Setup
    4. Verify callout with orange_background and '⚡' icon containing 'All code must pass linting and have 80%+ test coverage'
    5. Verify heading_3 'Code Review Checklist' exists after the callout
    6. Verify exactly 4 unchecked to-do blocks with required content
    7. Find 'Environment Variables' heading_3
    8. Verify code block with language 'bash' exists AFTER Environment Variables heading but BEFORE .env.example paragraph
    9. Verify code block contains required environment variables
    10. Verify bookmark block at the end with URL 'https://docs.acme.dev' and caption
    
    Weights: All-or-nothing (1.0 if all pass, 0.0 otherwise)
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    
    # 1. Find the Engineering Wiki page
    try:
        engineering_wiki = _find_page_by_title(final_state_backend, "Engineering Wiki")
        if not engineering_wiki:
            errors.append("[X] Engineering Wiki page not found")
        else:
            checks_passed.append("[C] Engineering Wiki page found")
    
        page_id = engineering_wiki.get("_id")
        page_blocks = _get_blocks_for_page(final_state_backend, page_id)
    
        if not page_blocks:
            errors.append("[X] No blocks found on Engineering Wiki page")
        else:
            checks_passed.append("[C] blocks found on Engineering Wiki page")
    
        # Sort blocks by order
        page_blocks_sorted = sorted(page_blocks, key=lambda b: b.get("order", 0))
    
        # 2. Find key reference blocks: Tech Stack (heading2), Development Setup (heading2), Environment Variables (heading3)
        tech_stack_idx = None
        dev_setup_idx = None
        env_vars_idx = None
        env_example_paragraph_idx = None
    
        for idx, block in enumerate(page_blocks_sorted):
            content = block.get("content", "")
            content_lower = content.lower()
            block_type = block.get("type", "")
        
            if block_type == "heading2" and "tech stack" in content_lower:
                tech_stack_idx = idx
            elif block_type == "heading2" and "development setup" in content_lower:
                dev_setup_idx = idx
            elif block_type == "heading3" and "environment variables" in content_lower:
                env_vars_idx = idx
            elif block_type == "paragraph" and ".env.example" in content:
                env_example_paragraph_idx = idx
    
        if tech_stack_idx is None:
            errors.append("[X] heading_2 'Tech Stack' not found on Engineering Wiki page")
        else:
            checks_passed.append("[C] heading_2 'Tech Stack' found on Engineering Wiki page")
    
        if dev_setup_idx is None:
            errors.append("[X] heading_2 'Development Setup' not found on Engineering Wiki page")
        else:
            checks_passed.append("[C] heading_2 'Development Setup' found on Engineering Wiki page")
    
        if env_vars_idx is None:
            errors.append("[X] heading_3 'Environment Variables' not found on Engineering Wiki page")
        else:
            checks_passed.append("[C] heading_3 'Environment Variables' found on Engineering Wiki page")
    
        # 3. Find heading_2 '🔧 Development Standards' - must be AFTER Tech Stack bullets and BEFORE Development Setup
        dev_standards_idx = None
        dev_standards_block = None
        for idx, block in enumerate(page_blocks_sorted):
            content = block.get("content", "")
            content_lower = content.lower()
            block_type = block.get("type", "")
        
            if block_type == "heading2" and "development standards" in content_lower:
                dev_standards_idx = idx
                dev_standards_block = block
                break
    
        if dev_standards_idx is None:
            errors.append("[X] heading_2 '🔧 Development Standards' not found")
        else:
            checks_passed.append("[C] heading_2 '🔧 Development Standards' found")
    
        # Verify '🔧' emoji is present
        if "🔧" not in dev_standards_block.get("content", ""):
            errors.append(f"[X] heading_2 'Development Standards' should have '🔧' emoji. Got: '{dev_standards_block.get('content', '')}'")
        else:
            checks_passed.append(f"[C] heading_2 'Development Standards' should have '🔧' emoji. Got: '{dev_standards_block.get('content', '')}'")
    
        # Verify positioning: after Tech Stack (and its bullets) but before Development Setup
        if dev_standards_idx <= tech_stack_idx:
            errors.append(f"[X] '🔧 Development Standards' must appear AFTER 'Tech Stack' section (Standards at idx {dev_standards_idx}, Tech Stack at {tech_stack_idx})")
        else:
            checks_passed.append(f"[C] '🔧 Development Standards' must appear AFTER 'Tech Stack' section (Standards at idx {dev_standards_idx}, Tech Stack at {tech_stack_idx})")
    
        if dev_standards_idx >= dev_setup_idx:
            errors.append(f"[X] '🔧 Development Standards' must appear BEFORE 'Development Setup' section (Standards at idx {dev_standards_idx}, Dev Setup at {dev_setup_idx})")
        else:
            checks_passed.append(f"[C] '🔧 Development Standards' must appear BEFORE 'Development Setup' section (Standards at idx {dev_standards_idx}, Dev Setup at {dev_setup_idx})")
    
        # 4. Find callout with orange_background and '⚡' icon after Development Standards heading
        orange_callout = None
        orange_callout_idx = None
        for idx in range(dev_standards_idx + 1, len(page_blocks_sorted)):
            block = page_blocks_sorted[idx]
            if block.get("type") == "callout":
                props = block.get("properties", {})
                bg_color = props.get("backgroundColor", "").lower()
                icon = props.get("icon", "")
            
                if "orange" in bg_color and "⚡" in icon:
                    orange_callout = block
                    orange_callout_idx = idx
                    break
            # Stop if we hit Development Setup
            if block.get("type") == "heading2" and "development setup" in block.get("content", "").lower():
                break
    
        if not orange_callout:
            errors.append("[X] Callout with orange_background and '⚡' icon not found after Development Standards heading")
        else:
            checks_passed.append("[C] Callout with orange_background and '⚡' icon found after Development Standards heading")
    
        # Verify callout content
        callout_content = orange_callout.get("content", "")
        if "linting" not in callout_content.lower() or "80%" not in callout_content or "test coverage" not in callout_content.lower():
            errors.append(f"[X] Callout should contain 'All code must pass linting and have 80%+ test coverage'. Got: '{callout_content}'")
        else:
            checks_passed.append(f"[C] Callout should contain 'All code must pass linting and have 80%+ test coverage'. Got: '{callout_content}'")
    
        # 5. Find heading_3 'Code Review Checklist' after the callout
        code_review_heading_idx = None
        for idx in range(orange_callout_idx + 1, len(page_blocks_sorted)):
            block = page_blocks_sorted[idx]
            content = block.get("content", "")
            content_lower = content.lower()
            block_type = block.get("type", "")
        
            if block_type == "heading3" and "code review checklist" in content_lower:
                code_review_heading_idx = idx
                break
            # Stop if we hit Development Setup
            if block_type == "heading2" and "development setup" in content_lower:
                break
    
        if code_review_heading_idx is None:
            errors.append("[X] heading_3 'Code Review Checklist' not found after callout")
        else:
            checks_passed.append("[C] heading_3 'Code Review Checklist' found after callout")
    
        # 6. Verify exactly 4 unchecked to-do blocks with required content
        expected_todos = [
            "tests pass and coverage meets standards",
            "documentation is updated",
            "no console.log statements remain",
            "performance impact assessed"
        ]
    
        found_todos = []
        todo_blocks = []
        for idx in range(code_review_heading_idx + 1, len(page_blocks_sorted)):
            block = page_blocks_sorted[idx]
            block_type = block.get("type", "")
        
            if block_type == "todo":
                props = block.get("properties", {})
                is_checked = props.get("checked", False)
            
                if is_checked:
                    errors.append(f"[X] To-do block should be unchecked: '{block.get('content', '')}'")
                else:
                    checks_passed.append(f"[C] To-do block should be unchecked: '{block.get('content', '')}'")
            
                content_lower = block.get("content", "").lower()
                # Remove the ✓ prefix if present for matching
                content_normalized = content_lower.replace("✓", "").strip()
                found_todos.append(content_normalized)
                todo_blocks.append(block)
        
            # Stop if we hit the next section (Development Setup)
            if block_type in ["heading2", "heading3"]:
                if "development setup" in block.get("content", "").lower():
                    break
                # Also stop at any other heading that would indicate we've left the checklist section
                if block_type == "heading2":
                    break
    
        # Verify we found exactly 4 todos
        if len(found_todos) != 4:
            errors.append(f"[X] Expected exactly 4 to-do blocks under Code Review Checklist, found {len(found_todos)}")
        else:
            checks_passed.append(f"[C] Expected exactly 4 to-do blocks under Code Review Checklist, found {len(found_todos)}")
    
        # Verify each expected todo is present
        for expected in expected_todos:
            found = False
            for todo_content in found_todos:
                if expected in todo_content:
                    found = True
                    break
            if not found:
                errors.append(f"[X] To-do block with '{expected}' not found. Found todos: {found_todos}")
            else:
                checks_passed.append(f"[C] To-do block with '{expected}' found. Found todos: {found_todos}")
    
        # 7 & 8. Find code block with language 'bash' AFTER Environment Variables heading but BEFORE .env.example paragraph
        bash_code_block = None
        bash_code_idx = None
    
        # Need to re-find env_vars_idx and env_example_paragraph_idx in the new sorted order
        env_vars_idx = None
        env_example_paragraph_idx = None
        for idx, block in enumerate(page_blocks_sorted):
            content = block.get("content", "")
            block_type = block.get("type", "")
        
            if block_type == "heading3" and "environment variables" in content.lower():
                env_vars_idx = idx
            elif block_type == "paragraph" and ".env.example" in content:
                env_example_paragraph_idx = idx
    
        if env_vars_idx is None:
            errors.append("[X] heading_3 'Environment Variables' not found")
        else:
            checks_passed.append("[C] heading_3 'Environment Variables' found")
    
        # Find bash code block after Environment Variables
        for idx in range(env_vars_idx + 1, len(page_blocks_sorted)):
            block = page_blocks_sorted[idx]
            if block.get("type") == "code":
                props = block.get("properties", {})
                language = props.get("language", "").lower()
                if language == "bash":
                    bash_code_block = block
                    bash_code_idx = idx
                    break
    
        if not bash_code_block:
            errors.append("[X] Code block with language 'bash' not found after Environment Variables heading")
        else:
            checks_passed.append("[C] Code block with language 'bash' found after Environment Variables heading")
    
        # Verify code block is before .env.example paragraph (if it exists)
        if env_example_paragraph_idx is not None and bash_code_idx >= env_example_paragraph_idx:
            errors.append(f"[X] Bash code block must appear BEFORE the .env.example paragraph (Code at idx {bash_code_idx}, Paragraph at {env_example_paragraph_idx})")
        else:
            checks_passed.append(f"[C] Bash code block must appear BEFORE the .env.example paragraph (Code at idx {bash_code_idx}, Paragraph at {env_example_paragraph_idx})")
    
        # 9. Verify code block content
        code_content = bash_code_block.get("content", "")
        required_env_vars = [
            "DATABASE_URL=mongodb://localhost:27017/acme",
            "REDIS_URL=redis://localhost:6379",
            "JWT_SECRET=your-secret-here",
            "NODE_ENV=development"
        ]
    
        for env_var in required_env_vars:
            if env_var not in code_content:
                errors.append(f"[X] Code block missing required environment variable: '{env_var}'. Got: '{code_content}'")
            else:
                checks_passed.append(f"[C] Code block has required environment variable: '{env_var}'. Got: '{code_content}'")
    
        # 10. Find bookmark block at the end of the page
        bookmark_block = None
        for block in reversed(page_blocks_sorted):
            if block.get("type") == "bookmark":
                bookmark_block = block
                break
    
        if not bookmark_block:
            errors.append("[X] Bookmark block not found at the end of the page")
        else:
            checks_passed.append("[C] Bookmark block found at the end of the page")
    
        # Verify bookmark URL and caption
        props = bookmark_block.get("properties", {})
        bookmark_url = props.get("url", "")
        bookmark_caption = props.get("caption", "")
    
        # Also check content field as some implementations store URL there
        if not bookmark_url:
            bookmark_url = bookmark_block.get("content", "")
    
        if "docs.acme.dev" not in bookmark_url:
            errors.append(f"[X] Bookmark URL should be 'https://docs.acme.dev'. Got: '{bookmark_url}'")
        else:
            checks_passed.append(f"[C] Bookmark URL should be 'https://docs.acme.dev'. Got: '{bookmark_url}'")
    
        if "api reference" not in bookmark_caption.lower() and "full api reference documentation" not in str(bookmark_block).lower():
            # Check if caption is in content or properties
            block_str = str(bookmark_block).lower()
            if "api reference" not in block_str and "documentation" not in block_str:
                errors.append(f"[X] Bookmark caption should contain 'Full API Reference Documentation'. Got properties: {props}")
            else:
                checks_passed.append(f"[C] Bookmark caption should contain 'Full API Reference Documentation'. Got properties: {props}")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_engineering_wiki_knowledge_base_index(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate Engineering Wiki Knowledge Base Index task.
    
    Goal: Navigate to 'Engineering Wiki' page and create an advanced knowledge base index
    with intelligent categorization and content analysis.
    
    Validation steps:
    1. Verify on Engineering Wiki page (page-4)
    2. Check heading_2 '🗂️ Knowledge Base Index' exists immediately after main heading
    3. Verify callouts for each original heading_2 section (Tech Stack, Development Setup)
       with gray_background, no icon, and correct subsection/block counts
    4. Check heading_3 '📊 Content Distribution' exists after callouts
    5. Verify bulleted list with percentage distribution (Technical, Process, Reference)
    6. Check heading_3 '🔍 Quick Links' exists
    7. Verify numbered list with all heading_3 blocks formatted correctly
    
    Weights:
    - Knowledge Base Index heading in correct position: 15%
    - Section callouts with correct format and counts: 25%
    - Content Distribution heading and list: 25%
    - Quick Links heading and list: 25%
    - Percentages add up to 100%: 10%
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    # Get all pages and blocks
    
    # 1. Find Engineering Wiki page
    try:
        eng_wiki_page = _find_page_by_title(final_state_backend, "Engineering Wiki")
        if not eng_wiki_page:
            errors.append("[X] Engineering Wiki page not found")
        else:
            checks_passed.append("[C] Engineering Wiki page found")
    
        eng_wiki_page_id = eng_wiki_page.get("_id")
    
        # Get all blocks for the page, sorted by order
        page_blocks = _get_blocks_for_page(final_state_backend, eng_wiki_page_id)
        page_blocks_sorted = sorted(page_blocks, key=lambda b: b.get("order", 0))
    
        if len(page_blocks_sorted) == 0:
            errors.append("[X] Engineering Wiki page has no blocks")
        else:
            checks_passed.append("[C] Engineering Wiki page has blocks")
    
        # 2. Check main heading exists (heading1 with "Engineering Wiki")
        main_heading_idx = None
        for idx, block in enumerate(page_blocks_sorted):
            if block.get("type") == "heading1":
                content = block.get("content", "").lower()
                if "engineering wiki" in content:
                    main_heading_idx = idx
                    break
    
        if main_heading_idx is None:
            errors.append("[X] Main heading 'Engineering Wiki' not found")
        else:
            checks_passed.append("[C] Main heading 'Engineering Wiki' found")
    
        # 3. Check heading_2 '🗂️ Knowledge Base Index' immediately after main heading
        knowledge_base_idx = None
        for idx, block in enumerate(page_blocks_sorted):
            if block.get("type") == "heading2":
                content = block.get("content", "")
                if "knowledge base index" in content.lower() and "🗂️" in content:
                    knowledge_base_idx = idx
                    break
    
        if knowledge_base_idx is None:
            errors.append("[X] heading_2 '🗂️ Knowledge Base Index' not found")
        else:
            checks_passed.append("[C] heading_2 '🗂️ Knowledge Base Index' found")
    
        if knowledge_base_idx <= main_heading_idx:
            errors.append("[X] Knowledge Base Index must be AFTER the main heading")
        else:
            checks_passed.append("[C] Knowledge Base Index must be AFTER the main heading")
    
        # Check that no other heading_2 from original content appears before Knowledge Base Index
        # Original heading_2s are "Tech Stack" and "Development Setup"
        for idx in range(main_heading_idx + 1, knowledge_base_idx):
            block = page_blocks_sorted[idx]
            if block.get("type") == "heading2":
                content = block.get("content", "").lower()
                if "tech stack" in content or "development setup" in content:
                    errors.append("[X] Knowledge Base Index must appear before original section headings")
                else:
                    checks_passed.append("[C] Knowledge Base Index must appear before original section headings")
    
        # 4. Find section callouts after Knowledge Base Index heading
        # Original sections: Tech Stack, Development Setup
        # Each callout should have gray_background, no icon, format: '[Section Name] - [X] subsections, [Y] total blocks'
    
        tech_stack_callout_found = False
        dev_setup_callout_found = False
    
        for idx in range(knowledge_base_idx + 1, len(page_blocks_sorted)):
            block = page_blocks_sorted[idx]
            block_type = block.get("type", "")
            content = block.get("content", "").lower()
            props = block.get("properties", {})
        
            # Stop when we hit Content Distribution heading
            if block_type == "heading3" and "content distribution" in content:
                break
        
            if block_type == "callout":
                bg_color = props.get("backgroundColor", "")
                icon = props.get("icon", "")
            
                # Check gray background
                if "gray" not in bg_color.lower():
                    errors.append(f"[X] Section callout must have gray_background, found: {bg_color}")
                else:
                    checks_passed.append(f"[C] Section callout must have gray_background, found: {bg_color}")
            
                # Check no icon (empty or not present)
                if icon and icon.strip():
                    errors.append(f"[X] Section callout must have no icon, found: {icon}")
                else:
                    checks_passed.append(f"[C] Section callout must have icon, found: {icon}")
            
                # Check content format
                if "tech stack" in content:
                    if "subsection" in content and "block" in content:
                        tech_stack_callout_found = True
                elif "development setup" in content:
                    if "subsection" in content and "block" in content:
                        dev_setup_callout_found = True
    
        if not tech_stack_callout_found:
            errors.append("[X] Callout for 'Tech Stack' section not found with correct format")
        else:
            checks_passed.append("[C] Callout for 'Tech Stack' section found with correct format")
    
        if not dev_setup_callout_found:
            errors.append("[X] Callout for 'Development Setup' section not found with correct format")
        else:
            checks_passed.append("[C] Callout for 'Development Setup' section found with correct format")
    
        # 5. Find heading_3 '📊 Content Distribution' after callouts
        content_dist_idx = None
        for idx, block in enumerate(page_blocks_sorted):
            if block.get("type") == "heading3":
                content = block.get("content", "")
                if "content distribution" in content.lower() and "📊" in content:
                    content_dist_idx = idx
                    break
    
        if content_dist_idx is None:
            errors.append("[X] heading_3 '📊 Content Distribution' not found")
        else:
            checks_passed.append("[C] heading_3 '📊 Content Distribution' found")
    
        if content_dist_idx <= knowledge_base_idx:
            errors.append("[X] Content Distribution heading must be after Knowledge Base Index heading")
        else:
            checks_passed.append("[C] Content Distribution heading must be after Knowledge Base Index heading")
    
        # 6. Verify bulleted list with percentage distribution
        # Look for bullets with Technical documentation, Process documentation, Reference material
        technical_pct_found = False
        process_pct_found = False
        reference_pct_found = False
        percentages = []
    
        for idx in range(content_dist_idx + 1, len(page_blocks_sorted)):
            block = page_blocks_sorted[idx]
            block_type = block.get("type", "")
            content = block.get("content", "").lower()
        
            # Stop when we hit the next heading
            if block_type in ["heading2", "heading3"]:
                break
        
            if block_type == "bulletedList":
                # Extract percentage using regex
                pct_match = re.search(r'(\d+(?:\.\d+)?)\s*%', content)
                if pct_match:
                    pct_value = float(pct_match.group(1))
                    percentages.append(pct_value)
            
                if "technical documentation" in content:
                    technical_pct_found = True
                elif "process documentation" in content:
                    process_pct_found = True
                elif "reference material" in content:
                    reference_pct_found = True
    
        if not technical_pct_found:
            errors.append("[X] Bulleted list item for 'Technical documentation' with percentage not found")
        else:
            checks_passed.append("[C] Bulleted list item for 'Technical documentation' with percentage found")
    
        if not process_pct_found:
            errors.append("[X] Bulleted list item for 'Process documentation' with percentage not found")
        else:
            checks_passed.append("[C] Bulleted list item for 'Process documentation' with percentage found")
    
        if not reference_pct_found:
            errors.append("[X] Bulleted list item for 'Reference material' with percentage not found")
        else:
            checks_passed.append("[C] Bulleted list item for 'Reference material' with percentage found")
    
        # Check percentages add up to 100% (with tolerance)
        if len(percentages) >= 3:
            total_pct = sum(percentages[:3])  # Take first 3 percentages
            if abs(total_pct - 100.0) > 1.0:  # Allow 1% tolerance for rounding
                errors.append(f"[X] Content distribution percentages must add up to 100%, got {total_pct}%")
            else:
                checks_passed.append(f"[C] Content distribution percentages must add up to 100%, got {total_pct}%")
    
        # 7. Find heading_3 '🔍 Quick Links'
        quick_links_idx = None
        for idx, block in enumerate(page_blocks_sorted):
            if block.get("type") == "heading3":
                content = block.get("content", "")
                if "quick links" in content.lower() and "🔍" in content:
                    quick_links_idx = idx
                    break
    
        if quick_links_idx is None:
            errors.append("[X] heading_3 '🔍 Quick Links' not found")
        else:
            checks_passed.append("[C] heading_3 '🔍 Quick Links' found")
    
        if quick_links_idx <= content_dist_idx:
            errors.append("[X] Quick Links heading must be after Content Distribution heading")
        else:
            checks_passed.append("[C] Quick Links heading must be after Content Distribution heading")
    
        # 8. Verify numbered list with heading_3 blocks
        # Original heading_3: "Environment Variables" (under Development Setup)
        # Format: '[Number]. 📍 [Heading text] (under [Parent Section])'
        env_vars_link_found = False
    
        for idx in range(quick_links_idx + 1, len(page_blocks_sorted)):
            block = page_blocks_sorted[idx]
            block_type = block.get("type", "")
            content = block.get("content", "").lower()
        
            # Stop when we hit another heading
            if block_type in ["heading2", "heading3"]:
                break
        
            if block_type == "numberedList":
                # Check for Environment Variables entry with parent section reference
                if "environment variables" in content and "📍" in block.get("content", ""):
                    if "development setup" in content or "parent" in content or "under" in content:
                        env_vars_link_found = True
    
        if not env_vars_link_found:
            errors.append("[X] Numbered list entry for 'Environment Variables' with '📍' and parent section reference not found")
        else:
            checks_passed.append("[C] Numbered list entry for 'Environment Variables' with '📍' and parent section reference found")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

    # -----------------------------------------------------------------------------
    # Task: company-handbook-surgical-modifications
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_company_handbook_surgical_modifications(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Company Handbook surgical modifications task.
    
    Goal: Perform surgical modifications on the Company Handbook page including:
    1. Swap 'Our Values' and 'Work Policies' sections completely
    2. Add divider block after Benefits numbered list items
    3. Add yellow callout with 💰 icon after divider
    4. Add 'Meeting Guidelines' heading3 after 'Time Off' in relocated Work Policies
    5. Add paragraph with core hours text after Meeting Guidelines heading
    
    Validation steps (ordered):
    1. Find Company Handbook page (page-16)
    2. Verify 'Work Policies' section (heading2) now appears BEFORE 'Our Values' section
    3. Verify all Work Policies subsections preserved (Remote Work, Time Off)
    4. Verify new heading3 'Meeting Guidelines' exists after 'Time Off' subsection
    5. Verify paragraph with exact core hours text after Meeting Guidelines
    6. Verify 'Our Values' section appears after Work Policies with all bullet points
    7. Verify 'Benefits' section with all numbered list items
    8. Verify divider block exists after last numbered list item in Benefits
    9. Verify yellow callout with 💰 icon and exact text after divider
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    
    # 1. Find 'Company Handbook' page
    try:
        handbook_page = _find_page_by_title(final_state_backend, "Company Handbook")
        if not handbook_page:
            errors.append("[X] Company Handbook page not found")
        else:
            checks_passed.append("[C] Company Handbook page found")
    
        page_id = handbook_page.get("_id")
        page_blocks = _get_blocks_for_page(final_state_backend, page_id)
    
        if not page_blocks:
            errors.append("[X] No blocks found on Company Handbook page")
        else:
            checks_passed.append("[C] blocks found on Company Handbook page")
    
        # Sort blocks by order
        page_blocks_sorted = sorted(page_blocks, key=lambda b: b.get("order", 0))
    
        # 2. Find the positions of key sections
        work_policies_idx = None
        our_values_idx = None
        remote_work_idx = None
        time_off_idx = None
        meeting_guidelines_idx = None
        benefits_idx = None
    
        for idx, block in enumerate(page_blocks_sorted):
            block_type = block.get("type", "")
            content = block.get("content", "").lower()
        
            if block_type == "heading2" and "work policies" in content:
                work_policies_idx = idx
            elif block_type == "heading2" and "our values" in content:
                our_values_idx = idx
            elif block_type == "heading3" and "remote work" in content:
                remote_work_idx = idx
            elif block_type == "heading3" and "time off" in content:
                time_off_idx = idx
            elif block_type == "heading3" and "meeting guidelines" in content:
                meeting_guidelines_idx = idx
            elif block_type == "heading2" and "benefits" in content:
                benefits_idx = idx
    
        # Validation 1: Work Policies must appear before Our Values (sections swapped)
        if work_policies_idx is None:
            errors.append("[X] heading_2 'Work Policies' not found")
        else:
            checks_passed.append("[C] heading_2 'Work Policies' found")
    
        if our_values_idx is None:
            errors.append("[X] heading_2 'Our Values' not found")
        else:
            checks_passed.append("[C] heading_2 'Our Values' found")
    
        if work_policies_idx >= our_values_idx:
            errors.append(f"[X] 'Work Policies' (idx {work_policies_idx}) must appear BEFORE 'Our Values' (idx {our_values_idx}) - sections not swapped correctly")
        else:
            checks_passed.append(f"[C] 'Work Policies' (idx {work_policies_idx}) must appear BEFORE 'Our Values' (idx {our_values_idx}) - sections swapped correctly")
    
        # Validation 2: Verify Work Policies subsections are preserved
        if remote_work_idx is None:
            errors.append("[X] heading_3 'Remote Work' not found under Work Policies")
        else:
            checks_passed.append("[C] heading_3 'Remote Work' found under Work Policies")
    
        if time_off_idx is None:
            errors.append("[X] heading_3 'Time Off' not found under Work Policies")
        else:
            checks_passed.append("[C] heading_3 'Time Off' found under Work Policies")
    
        # Verify Remote Work and Time Off are within Work Policies section (before Our Values)
        if remote_work_idx <= work_policies_idx or remote_work_idx >= our_values_idx:
            errors.append(f"[X] 'Remote Work' must be between 'Work Policies' and 'Our Values'")
        else:
            checks_passed.append(f"[C] 'Remote Work' must be between 'Work Policies' and 'Our Values'")
    
        if time_off_idx <= work_policies_idx or time_off_idx >= our_values_idx:
            errors.append(f"[X] 'Time Off' must be between 'Work Policies' and 'Our Values'")
        else:
            checks_passed.append(f"[C] 'Time Off' must be between 'Work Policies' and 'Our Values'")
    
        # Validation 3: New heading3 'Meeting Guidelines' must exist after 'Time Off'
        if meeting_guidelines_idx is None:
            errors.append("[X] heading_3 'Meeting Guidelines' not found")
        else:
            checks_passed.append("[C] heading_3 'Meeting Guidelines' found")
    
        if meeting_guidelines_idx <= time_off_idx:
            errors.append(f"[X] 'Meeting Guidelines' (idx {meeting_guidelines_idx}) must appear AFTER 'Time Off' (idx {time_off_idx})")
        else:
            checks_passed.append(f"[C] 'Meeting Guidelines' (idx {meeting_guidelines_idx}) must appear AFTER 'Time Off' (idx {time_off_idx})")
    
        if meeting_guidelines_idx >= our_values_idx:
            errors.append(f"[X] 'Meeting Guidelines' must appear BEFORE 'Our Values' section")
        else:
            checks_passed.append(f"[C] 'Meeting Guidelines' must appear BEFORE 'Our Values' section")
    
        # Validation 4: Verify paragraph with exact core hours text after Meeting Guidelines
        expected_core_hours_text = "core hours are 10am-3pm in your local timezone. schedule meetings within these hours when possible."
        core_hours_found = False
    
        for idx in range(meeting_guidelines_idx + 1, our_values_idx):
            block = page_blocks_sorted[idx]
            if block.get("type") == "paragraph":
                content = block.get("content", "").lower()
                if expected_core_hours_text in content:
                    core_hours_found = True
                    break
            # Stop if we hit another heading
            elif block.get("type") in ["heading1", "heading2", "heading3"]:
                break
    
        if not core_hours_found:
            errors.append(f"[X] Paragraph with core hours text not found after 'Meeting Guidelines'")
        else:
            checks_passed.append(f"[C] Paragraph with core hours text found after 'Meeting Guidelines'")
    
        # Validation 5: Verify Our Values section has its bullet points preserved
        our_values_bullets = []
        expected_values = [
            "customer first",
            "excellence",
            "collaboration"
        ]
    
        # Find bullets between Our Values and Benefits
        if benefits_idx is None:
            errors.append("[X] heading_2 'Benefits' not found")
        else:
            checks_passed.append("[C] heading_2 'Benefits' found")
    
        for idx in range(our_values_idx + 1, benefits_idx):
            block = page_blocks_sorted[idx]
            if block.get("type") in ["bulletedList", "bulleted_list"]:
                content = block.get("content", "").lower()
                for expected in expected_values:
                    if expected in content:
                        our_values_bullets.append(expected)
                        break
    
        # Remove duplicates
        our_values_bullets = list(set(our_values_bullets))
    
        if len(our_values_bullets) < 3:
            missing = [v for v in expected_values if v not in our_values_bullets]
            errors.append(f"[X] Missing Our Values bullet points: {missing}")
        else:
            checks_passed.append(f"[C] has Our Values bullet points: {has}")
    
        # Validation 6: Verify Benefits section with numbered list items
        expected_benefits = [
            "comprehensive health insurance",
            "401(k) matching",
            "annual learning stipend",
            "home office setup"
        ]
    
        benefits_items = []
        last_numbered_list_idx = None
    
        for idx in range(benefits_idx + 1, len(page_blocks_sorted)):
            block = page_blocks_sorted[idx]
            if block.get("type") in ["numberedList", "numbered_list"]:
                content = block.get("content", "").lower()
                for expected in expected_benefits:
                    if expected in content:
                        benefits_items.append(expected)
                        last_numbered_list_idx = idx
                        break
            # Stop if we hit another heading2
            elif block.get("type") == "heading2":
                break
    
        # Remove duplicates
        benefits_items = list(set(benefits_items))
    
        if len(benefits_items) < 4:
            missing = [b for b in expected_benefits if b not in benefits_items]
            errors.append(f"[X] Missing Benefits numbered list items: {missing}")
        else:
            checks_passed.append(f"[C] has Benefits numbered list items: {has}")
    
        if last_numbered_list_idx is None:
            errors.append("[X] No numbered list items found in Benefits section")
        else:
            checks_passed.append("[C] numbered list items found in Benefits section")
    
        # Validation 7: Verify divider block exists after last numbered list item
        divider_found = False
        divider_idx = None
    
        for idx in range(last_numbered_list_idx + 1, len(page_blocks_sorted)):
            block = page_blocks_sorted[idx]
            if block.get("type") == "divider":
                divider_found = True
                divider_idx = idx
                break
            # Stop if we hit another heading
            elif block.get("type") in ["heading1", "heading2"]:
                break
    
        if not divider_found:
            errors.append("[X] Divider block not found after Benefits numbered list items")
        else:
            checks_passed.append("[C] Divider block found after Benefits numbered list items")
    
        # Validation 8: Verify yellow callout with 💰 icon and exact text after divider
        expected_callout_text = "all benefits are effective from your first day of employment"
        callout_found = False
        callout_valid = False
    
        for idx in range(divider_idx + 1, len(page_blocks_sorted)):
            block = page_blocks_sorted[idx]
            if block.get("type") == "callout":
                content = block.get("content", "").lower()
                properties = block.get("properties", {})
            
                # Check for yellow background
                background = properties.get("background", properties.get("backgroundColor", ""))
                icon = properties.get("icon", "")
            
                callout_found = True
            
                # Check content
                if expected_callout_text not in content:
                    errors.append(f"[X] Callout found but text doesn't match. Expected: '{expected_callout_text}'")
                else:
                    checks_passed.append(f"[C] Callout found but text doesn't match. Expected: '{expected_callout_text}'")
            
                # Check yellow background
                if "yellow" not in background.lower():
                    errors.append(f"[X] Callout found but background is not yellow. Found: '{background}'")
                else:
                    checks_passed.append(f"[C] Callout found but background is yellow. Found: '{background}'")
            
                # Check icon
                if "💰" not in icon:
                    errors.append(f"[X] Callout found but icon is not 💰. Found: '{icon}'")
                else:
                    checks_passed.append(f"[C] Callout found but icon is 💰. Found: '{icon}'")
            
                callout_valid = True
                break
            # Stop if we hit another heading
            elif block.get("type") in ["heading1", "heading2"]:
                break
    
        if not callout_found:
            errors.append("[X] Callout block not found after divider in Benefits section")
        else:
            checks_passed.append("[C] Callout block found after divider in Benefits section")
    
        if not callout_valid:
            errors.append("[X] Callout found but validation failed")
        else:
            checks_passed.append("[C] Callout found but validation succeeded")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

    # -----------------------------------------------------------------------------
    # Task: workspace-migration-checklist
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_workspace_migration_checklist(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate Workspace Migration Checklist task.
    
    Goal: Create a comprehensive 'Workspace Migration Checklist' page at the workspace root
    that analyzes and documents content across both workspaces with accurate statistics.
    
    Validation steps (ordered):
    1. Find the 'Workspace Migration Checklist' page at workspace root (no parentId)
    2. Verify heading_1 '🚀 Workspace Migration Checklist' exists
    3. Verify heading_2 for workspace-1 content inventory ('Acme Corporation Content Inventory' or similar)
    4. Verify bullet points with statistics for workspace-1: Total pages: 49, Pages with sub-pages: 7, Favorited pages: 12
    5. Verify heading_2 for workspace-2 content inventory ('Starlight Design Studio Content Inventory' or similar)
    6. Verify bullet points with statistics for workspace-2: Total pages: 18, Pages with sub-pages: 1, Favorited pages: 4
    7. Verify heading_2 '🔄 Cross-Workspace Dependencies'
    8. Verify Meeting Notes and Design System duplicates are mentioned
    9. Verify numbered list with migration steps (Archive duplicate, Consolidate Design System, Update parent-child)
    10. Verify callout with red_background, '⚠️' icon, containing 'Critical' and total page count (67)
    
    Weights: All-or-nothing (1.0 if all pass, 0.0 otherwise)
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    
    # 1. Find the 'Workspace Migration Checklist' page at workspace root (no parentId)
    try:
        checklist_result = final_state_backend.query({
            "collection": "pages",
            "filter": {
                "title": {"$regex": "Workspace Migration Checklist", "$options": "i"},
                "parentId": None
            }
        })
        checklist_page = checklist_result[0] if isinstance(checklist_result, list) and checklist_result else None
        if not checklist_page:
            errors.append("[X] Workspace Migration Checklist page not found at workspace root")
        else:
            checks_passed.append("[C] Workspace Migration Checklist page found at workspace root")

        page_id = checklist_page.get("_id")
        page_blocks = _get_blocks_for_page(final_state_backend, page_id)
    
        if not page_blocks:
            errors.append("[X] No blocks found on Workspace Migration Checklist page")
        else:
            checks_passed.append("[C] blocks found on Workspace Migration Checklist page")
    
        # Sort blocks by order
        page_blocks_sorted = sorted(page_blocks, key=lambda b: b.get("order", 0))
    
        # 2. Verify heading_1 '🚀 Workspace Migration Checklist' exists
        heading1_found = False
        for block in page_blocks_sorted:
            if block.get("type") == "heading1":
                content = block.get("content", "")
                if "🚀" in content and "workspace migration checklist" in content.lower():
                    heading1_found = True
                    break
    
        if not heading1_found:
            errors.append("[X] heading_1 '🚀 Workspace Migration Checklist' not found")
        else:
            checks_passed.append("[C] heading_1 '🚀 Workspace Migration Checklist' found")
    
        # 3. Verify heading_2 for workspace-1 content inventory
        ws1_heading_found = False
        for block in page_blocks_sorted:
            if block.get("type") == "heading2":
                content = block.get("content", "").lower()
                if ("workspace-1" in content or "acme" in content or "workspace 1" in content) and "content inventory" in content:
                    ws1_heading_found = True
                    break
    
        if not ws1_heading_found:
            errors.append("[X] heading_2 for workspace-1 Content Inventory not found")
        else:
            checks_passed.append("[C] heading_2 for workspace-1 Content Inventory found")
    
        # 4. Verify bullet points with statistics for workspace-1
        # Expected: Total pages: 49, Pages with sub-pages: 7, Favorited pages: 12
        bullet_content = " ".join([b.get("content", "") for b in page_blocks_sorted if b.get("type") in ["bulletedList", "bulleted_list", "paragraph"]])
        bullet_content_lower = bullet_content.lower()
    
        # Check for workspace-1 statistics (some tolerance for slight variations)
        ws1_total_found = False
        ws1_subpages_found = False
        ws1_favorites_found = False
    
        for block in page_blocks_sorted:
            content = block.get("content", "").lower()
            # Check for total pages around 49
            if "total pages" in content:
                if any(str(n) in content for n in range(45, 55)):  # Allow some tolerance
                    ws1_total_found = True
            # Check for pages with sub-pages around 7
            if "sub-pages" in content or "subpages" in content or "sub pages" in content:
                if any(str(n) in content for n in range(5, 10)):
                    ws1_subpages_found = True
            # Check for favorited pages around 12
            if "favorite" in content:
                if any(str(n) in content for n in range(10, 15)):
                    ws1_favorites_found = True
    
        # 5. Verify heading_2 for workspace-2 content inventory
        ws2_heading_found = False
        for block in page_blocks_sorted:
            if block.get("type") == "heading2":
                content = block.get("content", "").lower()
                if ("workspace-2" in content or "starlight" in content or "workspace 2" in content) and "content inventory" in content:
                    ws2_heading_found = True
                    break
    
        if not ws2_heading_found:
            errors.append("[X] heading_2 for workspace-2 Content Inventory not found")
        else:
            checks_passed.append("[C] heading_2 for workspace-2 Content Inventory found")
    
        # 6. Verify statistics for workspace-2
        # Expected: Total pages: 18, Pages with sub-pages: 1, Favorited pages: 4
        ws2_total_found = False
        ws2_subpages_found = False  
        ws2_favorites_found = False
    
        for block in page_blocks_sorted:
            content = block.get("content", "").lower()
            if "total pages" in content:
                if any(str(n) in content for n in range(15, 22)):  # Around 18
                    ws2_total_found = True
            if "sub-pages" in content or "subpages" in content or "sub pages" in content:
                if "1" in content or "one" in content:
                    ws2_subpages_found = True
            if "favorite" in content:
                if any(str(n) in content for n in range(3, 6)):  # Around 4
                    ws2_favorites_found = True
    
        # 7. Verify heading_2 '🔄 Cross-Workspace Dependencies'
        dependencies_heading_found = False
        for block in page_blocks_sorted:
            if block.get("type") == "heading2":
                content = block.get("content", "")
                if "🔄" in content and "cross-workspace" in content.lower() and "dependencies" in content.lower():
                    dependencies_heading_found = True
                    break
    
        if not dependencies_heading_found:
            errors.append("[X] heading_2 '🔄 Cross-Workspace Dependencies' not found")
        else:
            checks_passed.append("[C] heading_2 '🔄 Cross-Workspace Dependencies' found")
    
        # 8. Verify Meeting Notes and Design System duplicates are mentioned
        all_content = " ".join([b.get("content", "").lower() for b in page_blocks_sorted])
    
        if "meeting notes" not in all_content:
            errors.append("[X] Duplicate 'Meeting Notes' pages not mentioned")
        else:
            checks_passed.append("[C] Duplicate 'Meeting Notes' pages mentioned")
    
        if "design system" not in all_content:
            errors.append("[X] Duplicate 'Design System' pages not mentioned")
        else:
            checks_passed.append("[C] Duplicate 'Design System' pages mentioned")
    
        # 9. Verify numbered list with migration steps
        numbered_list_blocks = [b for b in page_blocks_sorted if b.get("type") in ["numberedList", "numbered_list"]]
        numbered_content = " ".join([b.get("content", "").lower() for b in numbered_list_blocks])
    
        # Also check paragraphs that might contain numbered items
        numbered_in_paragraphs = False
        for block in page_blocks_sorted:
            content = block.get("content", "").lower()
            if ("1." in content or "archive" in content) and "duplicate" in content:
                numbered_in_paragraphs = True
                break
    
        # Check for the three migration steps
        archive_step_found = "archive" in all_content and "duplicate" in all_content and "meeting notes" in all_content
        consolidate_step_found = "consolidate" in all_content and "design system" in all_content
        update_step_found = "parent-child" in all_content or "parent child" in all_content or ("update" in all_content and "relationship" in all_content)
    
        if not archive_step_found:
            errors.append("[X] Migration step '1. Archive duplicate Meeting Notes pages' not found")
        else:
            checks_passed.append("[C] Migration step '1. Archive duplicate Meeting Notes pages' found")
    
        if not consolidate_step_found:
            errors.append("[X] Migration step '2. Consolidate Design System pages from both workspaces' not found")
        else:
            checks_passed.append("[C] Migration step '2. Consolidate Design System pages from both workspaces' found")
    
        if not update_step_found:
            errors.append("[X] Migration step '3. Update parent-child relationships post-migration' not found")
        else:
            checks_passed.append("[C] Migration step '3. Update parent-child relationships post-migration' found")
    
        # 10. Verify callout with red_background, '⚠️' icon, containing 'Critical' and total page count
        red_callout_found = False
        for block in page_blocks_sorted:
            if block.get("type") == "callout":
                props = block.get("properties", {})
                bg_color = props.get("backgroundColor", "").lower()
                icon = props.get("icon", "")
                content = block.get("content", "").lower()
            
                # Check for red background
                if "red" not in bg_color:
                    continue
            
                # Check for warning icon
                if "⚠️" not in icon and "⚠" not in icon:
                    continue
            
                # Check for 'Critical' and total count (67 or around that)
                if "critical" in content:
                    # Check for total page count around 67
                    if any(str(n) in content for n in range(60, 75)):
                        red_callout_found = True
                        break
    
        if not red_callout_found:
            errors.append("[X] Callout with red_background, '⚠️' icon, 'Critical' message and total page count (~67) not found")
        else:
            checks_passed.append("[C] Callout with red_background, '⚠️' icon, 'Critical' message and total page count (~67) found")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

    # -----------------------------------------------------------------------------
    # Task: api-versioning-documentation
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_api_versioning_documentation(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate API versioning documentation task.
    
    Goal: Navigate to API Documentation page and add comprehensive API versioning
    and deprecation notice sections with specific block structure.
    
    Validation Plan:
    1. Find 'API Documentation' page in backend
    2. Get all blocks for the page, sorted by order
    3. Find the original last block to verify new content is appended after it
    4. Verify heading_2 '🔄 API Versioning' exists after original content
    5. Verify code block with language 'http' contains the three specified lines
    6. Verify blue callout with 📌 icon and compatibility message
    7. Verify heading_2 '⚠️ Deprecation Notice' exists and is the last section
    8. Verify red callout with 🚨 icon containing deprecation message with date
    9. Verify unchecked todo block about updating client applications
    
    Weights: All checks are equally important (binary pass/fail)
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    
    # 1. Find 'API Documentation' page
    try:
        api_docs_page = _find_page_by_title(final_state_backend, "API Documentation")
        if not api_docs_page:
            errors.append("[X] API Documentation page not found")
        else:
            checks_passed.append("[C] API Documentation page found")
    
        page_id = api_docs_page.get("_id")
        page_blocks = _get_blocks_for_page(final_state_backend, page_id)
    
        if not page_blocks:
            errors.append("[X] No blocks found on API Documentation page")
        else:
            checks_passed.append("[C] blocks found on API Documentation page")
    
        # Sort blocks by order to ensure correct sequence
        page_blocks_sorted = sorted(page_blocks, key=lambda b: b.get("order", 0))
    
        # 2. Find heading_2 '🔄 API Versioning' 
        api_versioning_heading_idx = None
        for idx, block in enumerate(page_blocks_sorted):
            if block.get("type") == "heading2":
                content = block.get("content", "")
                if "🔄" in content and "api versioning" in content.lower():
                    api_versioning_heading_idx = idx
                    break
    
        if api_versioning_heading_idx is None:
            errors.append("[X] heading_2 '🔄 API Versioning' not found")
        else:
            checks_passed.append("[C] heading_2 '🔄 API Versioning' found")
    
        # 3. Verify code block with language 'http' exists after the heading
        code_block_found = False
        code_block_idx = None
        for idx in range(api_versioning_heading_idx + 1, len(page_blocks_sorted)):
            block = page_blocks_sorted[idx]
            if block.get("type") == "code":
                props = block.get("properties", {})
                content = block.get("content", "")
                language = props.get("language", "").lower()
            
                # Check for http language
                if language == "http":
                    # Check content contains the required lines
                    if "GET /api/v2/users" in content and "X-API-Version: 2.0" in content and "Accept: application/json" in content:
                        code_block_found = True
                        code_block_idx = idx
                        break
                # Also accept if content has the right structure even without explicit language check
                elif "GET /api/v2/users" in content and "X-API-Version: 2.0" in content and "Accept: application/json" in content:
                    code_block_found = True
                    code_block_idx = idx
                    break
            # Stop if we hit the next heading
            if block.get("type") in ["heading1", "heading2"] and idx != api_versioning_heading_idx:
                break
    
        if not code_block_found:
            errors.append("[X] Code block with language 'http' containing 'GET /api/v2/users', 'X-API-Version: 2.0', and 'Accept: application/json' not found after API Versioning heading")
        else:
            checks_passed.append("[C] Code block with language 'http' containing 'GET /api/v2/users', 'X-API-Version: 2.0', and 'Accept: application/json' found after API Versioning heading")
    
        # 4. Verify blue callout with 📌 icon and compatibility message
        blue_callout_found = False
        blue_callout_idx = None
        search_start = code_block_idx + 1 if code_block_idx else api_versioning_heading_idx + 1
    
        for idx in range(search_start, len(page_blocks_sorted)):
            block = page_blocks_sorted[idx]
            if block.get("type") == "callout":
                props = block.get("properties", {})
                content = block.get("content", "").lower()
                bg_color = props.get("backgroundColor", "").lower()
                icon = props.get("icon", "")
            
                # Check for blue background
                if "blue" in bg_color:
                    # Check for 📌 icon
                    if "📌" in icon:
                        # Check for compatibility message
                        if "always specify the api version" in content and "compatibility" in content:
                            blue_callout_found = True
                            blue_callout_idx = idx
                            break
            # Stop if we hit deprecation notice heading
            if block.get("type") == "heading2":
                content = block.get("content", "").lower()
                if "deprecation" in content:
                    break
    
        if not blue_callout_found:
            errors.append("[X] Blue callout with 📌 icon and message 'Always specify the API version in your requests to ensure compatibility.' not found")
        else:
            checks_passed.append("[C] Blue callout with 📌 icon and message 'Always specify the API version in your requests to ensure compatibility.' found")
    
        # 5. Verify heading_2 '⚠️ Deprecation Notice' exists
        deprecation_heading_idx = None
        for idx, block in enumerate(page_blocks_sorted):
            if block.get("type") == "heading2":
                content = block.get("content", "")
                if "⚠️" in content and "deprecation notice" in content.lower():
                    deprecation_heading_idx = idx
                    break
    
        if deprecation_heading_idx is None:
            errors.append("[X] heading_2 '⚠️ Deprecation Notice' not found")
        else:
            checks_passed.append("[C] heading_2 '⚠️ Deprecation Notice' found")
    
        # 6. Verify deprecation heading comes after API versioning section
        if deprecation_heading_idx <= api_versioning_heading_idx:
            errors.append(f"[X] Deprecation Notice heading (idx {deprecation_heading_idx}) must come AFTER API Versioning heading (idx {api_versioning_heading_idx})")
        else:
            checks_passed.append(f"[C] Deprecation Notice heading (idx {deprecation_heading_idx}) must come AFTER API Versioning heading (idx {api_versioning_heading_idx})")
    
        # 7. Verify red callout with 🚨 icon containing deprecation message with date
        red_callout_found = False
        red_callout_idx = None
    
        for idx in range(deprecation_heading_idx + 1, len(page_blocks_sorted)):
            block = page_blocks_sorted[idx]
            if block.get("type") == "callout":
                props = block.get("properties", {})
                content = block.get("content", "").lower()
                bg_color = props.get("backgroundColor", "").lower()
                icon = props.get("icon", "")
            
                # Check for red background
                if "red" in bg_color:
                    # Check for 🚨 icon
                    if "🚨" in icon:
                        # Check for deprecation message - must mention v1.0 deprecation and migration to v2.0
                        if "version 1.0" in content and "deprecated" in content and "v2.0" in content:
                            # Should also have a date (90 days from today which would be April 2026)
                            # Allow flexible date checking - just verify there's a date mentioned
                            if any(month in content for month in ["january", "february", "march", "april", "may", "june", "july", "august", "september", "october", "november", "december", "jan", "feb", "mar", "apr", "may", "jun", "jul", "aug", "sep", "oct", "nov", "dec"]) or "2026" in content or "/" in content or "-" in content:
                                red_callout_found = True
                                red_callout_idx = idx
                                break
            # Stop if we hit another heading
            if block.get("type") in ["heading1", "heading2"] and idx != deprecation_heading_idx:
                break
    
        if not red_callout_found:
            errors.append("[X] Red callout with 🚨 icon containing 'Version 1.0 will be deprecated on [date]. Please migrate to v2.0.' not found after Deprecation Notice heading")
        else:
            checks_passed.append("[C] Red callout with 🚨 icon containing 'Version 1.0 will be deprecated on [date]. Please migrate to v2.0.' found after Deprecation Notice heading")
    
        # 8. Verify unchecked todo block about updating client applications
        todo_found = False
        search_start = red_callout_idx + 1 if red_callout_idx else deprecation_heading_idx + 1
    
        for idx in range(search_start, len(page_blocks_sorted)):
            block = page_blocks_sorted[idx]
            if block.get("type") == "todo":
                props = block.get("properties", {})
                content = block.get("content", "").lower()
            
                # Check for unchecked state
                is_checked = props.get("checked", False)
                if not is_checked:
                    # Check for content about updating client applications
                    if "update" in content and "client" in content and "api v2.0" in content:
                        todo_found = True
                        break
                    # Also accept variations
                    if "update all client applications" in content and "v2.0" in content:
                        todo_found = True
                        break
    
        if not todo_found:
            errors.append("[X] Unchecked todo block 'Update all client applications to use API v2.0' not found")
        else:
            checks_passed.append("[C] Unchecked todo block 'Update all client applications to use API v2.0' found")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

    # -----------------------------------------------------------------------------
    # Task: prd-document-structure
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_prd_document_structure(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate PRD Document Structure task.
    
    Goal: Navigate to 'Comprehensive Product Requirements Document' page and insert a 
    document structure section with accurate section counts based on heading_3 analysis.
    
    Validation steps:
    1. Find the 'Comprehensive Product Requirements Document' page (page-47)
    2. Verify heading_2 '📑 Document Structure' exists after main heading_1 but before 'Overview' heading_2
    3. Verify callout with gray_background containing 'This document contains 3 overview sections and 3 user story sections'
    4. Verify numbered list with 3 items:
       - 'Total document sections: 6'
       - 'Average content blocks per section: ~8'
       - 'Last updated: January 2024'
    5. Verify the new section appears between the main heading and the Overview heading
    
    Weights:
    - Document Structure heading in correct position: 20%
    - Callout with gray_background and correct text: 30%
    - Numbered list with correct content: 30%
    - Correct positioning (after heading_1, before Overview heading_2): 20%
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    # Get all pages and blocks
    
    # 1. Find the Comprehensive Product Requirements Document page
    try:
        prd_page = _find_page_by_title(final_state_backend, "Comprehensive Product Requirements Document")
        if not prd_page:
            errors.append("[X] Comprehensive Product Requirements Document page not found")
        else:
            checks_passed.append("[C] Comprehensive Product Requirements Document page found")
    
        prd_page_id = prd_page.get("_id")
    
        # Get all blocks for the page, sorted by order
        page_blocks = _get_blocks_for_page(final_state_backend, prd_page_id)
        page_blocks_sorted = sorted(page_blocks, key=lambda b: b.get("order", 0))
    
        if len(page_blocks_sorted) == 0:
            errors.append("[X] PRD page has no blocks")
        else:
            checks_passed.append("[C] PRD page has blocks")
    
        # 2. Find main heading_1 'Product Requirements Document'
        main_heading_idx = None
        for idx, block in enumerate(page_blocks_sorted):
            if block.get("type") == "heading1":
                content = block.get("content", "").lower()
                if "product requirements document" in content:
                    main_heading_idx = idx
                    break
    
        if main_heading_idx is None:
            errors.append("[X] Main heading_1 'Product Requirements Document' not found")
        else:
            checks_passed.append("[C] Main heading_1 'Product Requirements Document' found")
    
        # 3. Find the original 'Overview' heading_2
        original_overview_idx = None
        for idx, block in enumerate(page_blocks_sorted):
            if block.get("type") == "heading2":
                content = block.get("content", "").strip()
                # Look for the original Overview heading (not Document Structure)
                if content.lower() == "overview":
                    original_overview_idx = idx
                    break
    
        if original_overview_idx is None:
            errors.append("[X] Original 'Overview' heading_2 not found")
        else:
            checks_passed.append("[C] Original 'Overview' heading_2 found")
    
        # 4. Find heading_2 '📑 Document Structure'
        doc_structure_idx = None
        for idx, block in enumerate(page_blocks_sorted):
            if block.get("type") == "heading2":
                content = block.get("content", "")
                if "document structure" in content.lower() and "📑" in content:
                    doc_structure_idx = idx
                    break
    
        if doc_structure_idx is None:
            errors.append("[X] heading_2 '📑 Document Structure' not found")
        else:
            checks_passed.append("[C] heading_2 '📑 Document Structure' found")
    
        # 5. Verify Document Structure is after main heading and before Overview
        if doc_structure_idx <= main_heading_idx:
            errors.append("[X] Document Structure heading must be AFTER the main heading_1")
        else:
            checks_passed.append("[C] Document Structure heading must be AFTER the main heading_1")
    
        if doc_structure_idx >= original_overview_idx:
            errors.append("[X] Document Structure heading must be BEFORE the Overview heading_2")
        else:
            checks_passed.append("[C] Document Structure heading must be BEFORE the Overview heading_2")
    
        # 6. Find callout with gray_background after Document Structure heading
        callout_found = False
        callout_content_correct = False
    
        for idx in range(doc_structure_idx + 1, original_overview_idx):
            block = page_blocks_sorted[idx]
            if block.get("type") == "callout":
                props = block.get("properties", {})
                bg_color = props.get("backgroundColor", "")
                content = block.get("content", "")
            
                # Check for gray_background
                if "gray" in bg_color.lower():
                    callout_found = True
                
                    # Check content contains the exact required text with counts
                    content_lower = content.lower()
                    if ("3 overview sections" in content_lower and 
                        "3 user story sections" in content_lower):
                        callout_content_correct = True
                    else:
                        errors.append(f"[X] Callout content incorrect. Expected '3 overview sections and 3 user story sections'. Got: '{content}'")
                else:
                    errors.append(f"[X] Callout must have gray_background, found: '{bg_color}'")
                break
    
        if not callout_found:
            errors.append("[X] Callout with gray_background not found after Document Structure heading")
        else:
            checks_passed.append("[C] Callout with gray_background found after Document Structure heading")
    
        if not callout_content_correct:
            errors.append("[X] Callout content does not contain correct section counts")
        else:
            checks_passed.append("[C] Callout content does contains correct section counts")
    
        # 7. Find numbered list items after the callout
        numbered_list_items = []
        started_numbered_list = False
    
        for idx in range(doc_structure_idx + 1, original_overview_idx):
            block = page_blocks_sorted[idx]
            if block.get("type") == "numberedList":
                started_numbered_list = True
                numbered_list_items.append(block.get("content", ""))
            elif started_numbered_list and block.get("type") != "numberedList":
                # Numbered list ended
                break
    
        if len(numbered_list_items) < 3:
            errors.append(f"[X] Expected 3 numbered list items, found {len(numbered_list_items)}")
        else:
            checks_passed.append(f"[C] Found 3 numbered list items as expected")
    
        # 8. Verify numbered list content
        # Item 1: Total document sections: 6
        item1_content = numbered_list_items[0].lower()
        if "total document sections" not in item1_content or "6" not in item1_content:
            errors.append(f"[X] First numbered list item should contain 'Total document sections: 6'. Got: '{numbered_list_items[0]}'")
        else:
            checks_passed.append(f"[C] First numbered list item should contain 'Total document sections: 6'. Got: '{numbered_list_items[0]}'")
    
        # Item 2: Average content blocks per section: ~8
        item2_content = numbered_list_items[1].lower()
        if "average content blocks" not in item2_content or "8" not in item2_content:
            errors.append(f"[X] Second numbered list item should contain 'Average content blocks per section: ~8'. Got: '{numbered_list_items[1]}'")
        else:
            checks_passed.append(f"[C] Second numbered list item should contain 'Average content blocks per section: ~8'. Got: '{numbered_list_items[1]}'")
    
        # Item 3: Last updated: January 2024
        item3_content = numbered_list_items[2].lower()
        if "last updated" not in item3_content or "january 2024" not in item3_content:
            errors.append(f"[X] Third numbered list item should contain 'Last updated: January 2024'. Got: '{numbered_list_items[2]}'")
        else:
            checks_passed.append(f"[C] Third numbered list item should contain 'Last updated: January 2024'. Got: '{numbered_list_items[2]}'")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

    # -----------------------------------------------------------------------------
    # Task: feature-backlog-analysis
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_feature_backlog_analysis(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Feature Backlog Analysis page creation as sibling to Feature Requests.
    
    Goal: Create a new page '🎯 Feature Backlog Analysis' as sibling to 'Feature Requests',
    analyzing its to-do blocks and structuring with specific headings and content.
    
    Validation steps (ordered):
    1. Find the Feature Requests page to get its parent context
    2. Find the new '🎯 Feature Backlog Analysis' page as a sibling (same parent or both top-level)
    3. Verify heading_1 '🎯 Feature Backlog Analysis' exists
    4. Verify heading_2 with '📅 Analysis Date:' exists (with today's date)
    5. Verify quote block with exact text 'Features are the bridge between user needs and product evolution.'
    6. Verify heading_2 '🚀 Implementation Status'
    7. Verify heading_3 '✅ Shipped Features' with numbered list of checked todos
    8. Verify heading_3 '🔄 In Development' with paragraph 'No features currently in active development'
    9. Verify heading_3 '📝 Backlog Items' with numbered list of unchecked todos
    10. Verify blue callout with 💡 icon containing 'Recommendation: Prioritize Keyboard shortcuts customization for next sprint'
    
    Weights: All-or-nothing (1.0 if all pass, 0.0 otherwise)
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    
    # 1. Find the Feature Requests page
    try:
        feature_requests_page = _find_page_by_title(final_state_backend, "Feature Requests")
        if not feature_requests_page:
            errors.append("[X] Feature Requests page not found")
        else:
            checks_passed.append("[C] Feature Requests page found")
    
        feature_requests_parent = feature_requests_page.get("parentId")
    
        # Get todos from Feature Requests page for validation
        feature_requests_id = feature_requests_page.get("_id")
        feature_requests_blocks = _get_blocks_for_page(final_state_backend, feature_requests_id)
        feature_requests_blocks_sorted = sorted(feature_requests_blocks, key=lambda b: b.get("order", 0))
    
        # Extract checked and unchecked todos
        checked_todos = []
        unchecked_todos = []
        for block in feature_requests_blocks_sorted:
            if block.get("type") == "todo":
                content = block.get("content", "")
                props = block.get("properties", {})
                if props.get("checked", False):
                    checked_todos.append(content)
                else:
                    unchecked_todos.append(content)
    
        # Expected: Dark mode support (checked), Keyboard shortcuts customization (unchecked), Export to PDF functionality (unchecked)
        first_unchecked_todo = unchecked_todos[0] if unchecked_todos else ""
    
        # 2. Find the Feature Backlog Analysis page as a sibling
        backlog_result = final_state_backend.query({
            "collection": "pages",
            "filter": {
                "title": {"$regex": "Feature Backlog Analysis", "$options": "i"},
                "parentId": feature_requests_parent
            }
        })
        backlog_analysis_page = backlog_result[0] if isinstance(backlog_result, list) and backlog_result else None
        if not backlog_analysis_page:
            errors.append("[X] Page '🎯 Feature Backlog Analysis' not found as a sibling to 'Feature Requests'")
        else:
            checks_passed.append("[C] Page '🎯 Feature Backlog Analysis' found as a sibling to 'Feature Requests'")

        backlog_page_id = backlog_analysis_page.get("_id")
        backlog_blocks = _get_blocks_for_page(final_state_backend, backlog_page_id)
    
        if not backlog_blocks:
            errors.append("[X] No blocks found on Feature Backlog Analysis page")
        else:
            checks_passed.append("[C] blocks found on Feature Backlog Analysis page")
    
        # Sort blocks by order
        backlog_blocks_sorted = sorted(backlog_blocks, key=lambda b: b.get("order", 0))
    
        # 3. Verify heading_1 '🎯 Feature Backlog Analysis'
        heading1_found = False
        for block in backlog_blocks_sorted:
            if block.get("type") == "heading1":
                content = block.get("content", "")
                if "feature backlog analysis" in content.lower():
                    heading1_found = True
                    break
    
        if not heading1_found:
            errors.append("[X] heading_1 '🎯 Feature Backlog Analysis' not found")
        else:
            checks_passed.append("[C] heading_1 '🎯 Feature Backlog Analysis' found")
    
        # 4. Verify heading_2 with '📅 Analysis Date:' exists
        analysis_date_heading_found = False
        for block in backlog_blocks_sorted:
            if block.get("type") == "heading2":
                content = block.get("content", "")
                if "analysis date" in content.lower():
                    analysis_date_heading_found = True
                    break
    
        if not analysis_date_heading_found:
            errors.append("[X] heading_2 '📅 Analysis Date: [today's date]' not found")
        else:
            checks_passed.append("[C] heading_2 '📅 Analysis Date: [today's date]' found")
    
        # 5. Verify quote block with exact text
        quote_found = False
        expected_quote = "features are the bridge between user needs and product evolution"
        for block in backlog_blocks_sorted:
            if block.get("type") == "quote":
                content = block.get("content", "").lower()
                if expected_quote in content:
                    quote_found = True
                    break
    
        if not quote_found:
            errors.append("[X] Quote block 'Features are the bridge between user needs and product evolution.' not found")
        else:
            checks_passed.append("[C] Quote block 'Features are the bridge between user needs and product evolution.' found")
    
        # 6. Verify heading_2 '🚀 Implementation Status'
        implementation_status_found = False
        implementation_status_idx = None
        for idx, block in enumerate(backlog_blocks_sorted):
            if block.get("type") == "heading2":
                content = block.get("content", "")
                if "implementation status" in content.lower():
                    implementation_status_found = True
                    implementation_status_idx = idx
                    break
    
        if not implementation_status_found:
            errors.append("[X] heading_2 '🚀 Implementation Status' not found")
        else:
            checks_passed.append("[C] heading_2 '🚀 Implementation Status' found")
    
        # 7. Verify heading_3 '✅ Shipped Features'
        shipped_features_found = False
        shipped_features_idx = None
        for idx, block in enumerate(backlog_blocks_sorted):
            if block.get("type") == "heading3":
                content = block.get("content", "")
                if "shipped features" in content.lower():
                    shipped_features_found = True
                    shipped_features_idx = idx
                    break
    
        if not shipped_features_found:
            errors.append("[X] heading_3 '✅ Shipped Features' not found")
        else:
            checks_passed.append("[C] heading_3 '✅ Shipped Features' found")
    
        # Verify numbered list contains checked todos after Shipped Features heading
        numbered_list_after_shipped = []
        if shipped_features_idx is not None:
            for idx in range(shipped_features_idx + 1, len(backlog_blocks_sorted)):
                block = backlog_blocks_sorted[idx]
                block_type = block.get("type", "")
                if block_type == "numberedList":
                    numbered_list_after_shipped.append(block.get("content", ""))
                elif block_type.startswith("heading"):
                    break
    
        # Check that checked todos are in the numbered list
        for todo in checked_todos:
            found = any(todo.lower() in item.lower() for item in numbered_list_after_shipped)
            if not found:
                errors.append(f"[X] Checked todo '{todo}' not found in numbered list under 'Shipped Features'")
            else:
                checks_passed.append(f"[C] Checked todo '{todo}' found in numbered list under 'Shipped Features'")
    
        # 8. Verify heading_3 '🔄 In Development' with paragraph
        in_dev_found = False
        in_dev_idx = None
        for idx, block in enumerate(backlog_blocks_sorted):
            if block.get("type") == "heading3":
                content = block.get("content", "")
                if "in development" in content.lower():
                    in_dev_found = True
                    in_dev_idx = idx
                    break
    
        if not in_dev_found:
            errors.append("[X] heading_3 '🔄 In Development' not found")
        else:
            checks_passed.append("[C] heading_3 '🔄 In Development' found")
    
        # Verify paragraph 'No features currently in active development'
        no_features_para_found = False
        if in_dev_idx is not None:
            for idx in range(in_dev_idx + 1, len(backlog_blocks_sorted)):
                block = backlog_blocks_sorted[idx]
                block_type = block.get("type", "")
                if block_type == "paragraph":
                    content = block.get("content", "").lower()
                    if "no features currently in active development" in content:
                        no_features_para_found = True
                        break
                elif block_type.startswith("heading"):
                    break
    
        if not no_features_para_found:
            errors.append("[X] Paragraph 'No features currently in active development' not found under 'In Development'")
        else:
            checks_passed.append("[C] Paragraph 'features currently in active development' found under 'In Development'")
    
        # 9. Verify heading_3 '📝 Backlog Items'
        backlog_items_found = False
        backlog_items_idx = None
        for idx, block in enumerate(backlog_blocks_sorted):
            if block.get("type") == "heading3":
                content = block.get("content", "")
                if "backlog items" in content.lower():
                    backlog_items_found = True
                    backlog_items_idx = idx
                    break
    
        if not backlog_items_found:
            errors.append("[X] heading_3 '📝 Backlog Items' not found")
        else:
            checks_passed.append("[C] heading_3 '📝 Backlog Items' found")
    
        # Verify numbered list contains unchecked todos after Backlog Items heading
        numbered_list_after_backlog = []
        if backlog_items_idx is not None:
            for idx in range(backlog_items_idx + 1, len(backlog_blocks_sorted)):
                block = backlog_blocks_sorted[idx]
                block_type = block.get("type", "")
                if block_type == "numberedList":
                    numbered_list_after_backlog.append(block.get("content", ""))
                elif block_type.startswith("heading") or block_type == "callout":
                    break
    
        # Check that unchecked todos are in the numbered list
        for todo in unchecked_todos:
            found = any(todo.lower() in item.lower() for item in numbered_list_after_backlog)
            if not found:
                errors.append(f"[X] Unchecked todo '{todo}' not found in numbered list under 'Backlog Items'")
            else:
                checks_passed.append(f"[C] Unchecked todo '{todo}' found in numbered list under 'Backlog Items'")
    
        # 10. Verify blue callout with 💡 icon and recommendation text
        blue_callout_found = False
        for block in backlog_blocks_sorted:
            if block.get("type") == "callout":
                props = block.get("properties", {})
                bg_color = props.get("backgroundColor", "").lower()
                icon = props.get("icon", "")
                content = block.get("content", "").lower()
            
                if "blue" in bg_color and "💡" in icon:
                    # Check for recommendation text with first unchecked todo
                    if "recommendation" in content and "prioritize" in content:
                        if first_unchecked_todo.lower() in content and "next sprint" in content:
                            blue_callout_found = True
                            break
    
        if not blue_callout_found:
            errors.append(f"[X] Blue callout with 💡 icon and text 'Recommendation: Prioritize {first_unchecked_todo} for next sprint' not found")
        else:
            checks_passed.append(f"[C] Blue callout with 💡 icon and text 'Recommendation: Prioritize {first_unchecked_todo} for next sprint' found")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

    # -----------------------------------------------------------------------------
    # Task: team-retrospective-achievements-section
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_team_retrospective_achievements_section(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Team Retrospective achievements section insertion task.
    
    Goal: Add a '🎉 Team Achievements' section between 'What went well' and 
    'What could be improved' sections on the Team Retrospective page (page-3-2),
    including numbered list with 3 items, divider, and quote block.
    Additionally, ensure all heading3 blocks use emoji prefix pattern.
    
    Validation steps (ordered):
    1. Find the 'Team Retrospective' page (page-3-2)
    2. Get all blocks sorted by order
    3. Find 'What went well' heading3 and its section content
    4. Find 'What could be improved' heading3
    5. Verify new heading3 '🎉 Team Achievements' exists between sections
    6. Verify numbered list with exactly 3 items with specific content
    7. Verify divider block exists after the numbered list
    8. Verify quote block with specific text after the divider
    9. Verify all heading3 blocks have emoji prefix pattern
    
    Weights: All checks must pass (binary 0/1).
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    
    # 1. Find the 'Team Retrospective' page
    try:
        team_retro_page = _find_page_by_title(final_state_backend, "Team Retrospective")
        if not team_retro_page:
            errors.append("[X] Team Retrospective page not found")
        else:
            checks_passed.append("[C] Team Retrospective page found")
    
        page_id = team_retro_page.get("_id")
    
        # 2. Get all blocks for this page sorted by order
        page_blocks = _get_blocks_for_page(final_state_backend, page_id)
        page_blocks_sorted = sorted(page_blocks, key=lambda b: b.get("order", 0))
    
        if not page_blocks_sorted:
            errors.append("[X] No blocks found on Team Retrospective page")
        else:
            checks_passed.append("[C] blocks found on Team Retrospective page")
    
        # 3. Find 'What went well' heading3 and its section end
        what_went_well_idx = None
        what_went_well_order = None
        for idx, block in enumerate(page_blocks_sorted):
            content = block.get("content", "").lower()
            block_type = block.get("type", "")
            if block_type == "heading3" and "what went well" in content:
                what_went_well_idx = idx
                what_went_well_order = block.get("order", 0)
                break
    
        if what_went_well_idx is None:
            errors.append("[X] heading3 'What went well' not found")
        else:
            checks_passed.append("[C] heading3 'What went well' found")
    
        # 4. Find 'What could be improved' heading3
        what_could_improved_idx = None
        what_could_improved_order = None
        for idx, block in enumerate(page_blocks_sorted):
            content = block.get("content", "").lower()
            block_type = block.get("type", "")
            if block_type == "heading3" and "what could be improved" in content:
                what_could_improved_idx = idx
                what_could_improved_order = block.get("order", 0)
                break
    
        if what_could_improved_idx is None:
            errors.append("[X] heading3 'What could be improved' not found")
        else:
            checks_passed.append("[C] heading3 'What could be improved' found")
    
        # 5. Find heading3 '🎉 Team Achievements' - must exist between the two sections
        team_achievements_idx = None
        team_achievements_block = None
        for idx, block in enumerate(page_blocks_sorted):
            content = block.get("content", "")
            block_type = block.get("type", "")
            if block_type == "heading3" and "team achievements" in content.lower():
                team_achievements_idx = idx
                team_achievements_block = block
                break
    
        if team_achievements_idx is None:
            errors.append("[X] heading3 '🎉 Team Achievements' not found")
        else:
            checks_passed.append("[C] heading3 '🎉 Team Achievements' found")
    
        # Verify '🎉 Team Achievements' content has emoji prefix
        achievements_content = team_achievements_block.get("content", "")
        if "🎉" not in achievements_content:
            errors.append(f"[X] heading3 'Team Achievements' must have '🎉' emoji prefix. Found: '{achievements_content}'")
        else:
            checks_passed.append(f"[C] heading3 'Team Achievements' must have '🎉' emoji prefix. Found: '{achievements_content}'")
    
        # Verify position: Team Achievements must be after What went well but before What could be improved
        team_achievements_order = team_achievements_block.get("order", 0)
    
        if team_achievements_order <= what_went_well_order:
            errors.append(f"[X] '🎉 Team Achievements' (order {team_achievements_order}) must appear AFTER 'What went well' (order {what_went_well_order})")
        else:
            checks_passed.append(f"[C] '🎉 Team Achievements' (order {team_achievements_order}) must appear AFTER 'What went well' (order {what_went_well_order})")
    
        if team_achievements_order >= what_could_improved_order:
            errors.append(f"[X] '🎉 Team Achievements' (order {team_achievements_order}) must appear BEFORE 'What could be improved' (order {what_could_improved_order})")
        else:
            checks_passed.append(f"[C] '🎉 Team Achievements' (order {team_achievements_order}) must appear BEFORE 'What could be improved' (order {what_could_improved_order})")
    
        # 6. Verify numbered list with exactly 3 items with specific content
        required_list_items = [
            "shipped 3 major features ahead of schedule",
            "reduced bug count by 40% compared to last month",
            "improved deployment time from 45 to 12 minutes"
        ]
    
        # Find numbered list blocks between Team Achievements and What could be improved
        numbered_list_blocks = []
        for idx in range(team_achievements_idx + 1, len(page_blocks_sorted)):
            block = page_blocks_sorted[idx]
            block_order = block.get("order", 0)
        
            # Stop if we reach "What could be improved" section
            if block_order >= what_could_improved_order:
                break
        
            block_type = block.get("type", "")
            if block_type in ["numberedList", "numbered_list", "numberedListItem", "numbered_list_item"]:
                numbered_list_blocks.append(block)
    
        if len(numbered_list_blocks) != 3:
            errors.append(f"[X] Expected exactly 3 numbered list items after '🎉 Team Achievements', found {len(numbered_list_blocks)}")
        else:
            checks_passed.append(f"[C] Expected exactly 3 numbered list items after '🎉 Team Achievements', found {len(numbered_list_blocks)}")
    
        # Verify each required item is present
        found_items = []
        for block in numbered_list_blocks:
            content = block.get("content", "").lower()
            for required_item in required_list_items:
                if required_item in content:
                    found_items.append(required_item)
                    break
    
        missing_items = [item for item in required_list_items if item not in found_items]
        if missing_items:
            errors.append(f"[X] Missing numbered list items: {missing_items}")
        else:
            checks_passed.append(f"[C] has numbered list items: {missing_items}")
    
        # 7. Verify divider block exists after the numbered list but before "What could be improved"
        divider_found = False
        divider_order = None
        last_numbered_order = numbered_list_blocks[-1].get("order", 0) if numbered_list_blocks else team_achievements_order
    
        for block in page_blocks_sorted:
            block_order = block.get("order", 0)
            block_type = block.get("type", "")
        
            # Look for divider after numbered list but before "What could be improved"
            if block_order > last_numbered_order and block_order < what_could_improved_order:
                if block_type == "divider":
                    divider_found = True
                    divider_order = block_order
                    break
    
        if not divider_found:
            errors.append("[X] Divider block not found between numbered list and 'What could be improved' section")
        else:
            checks_passed.append("[C] Divider block found between numbered list and 'What could be improved' section")
    
        # 8. Verify quote block with specific text after the divider
        expected_quote = "success is not final, failure is not fatal: it is the courage to continue that counts"
        quote_found = False
    
        for block in page_blocks_sorted:
            block_order = block.get("order", 0)
            block_type = block.get("type", "")
        
            # Look for quote after divider but before "What could be improved"
            if block_order > divider_order and block_order < what_could_improved_order:
                if block_type == "quote":
                    content = block.get("content", "").lower()
                    if expected_quote in content:
                        quote_found = True
                        break
    
        if not quote_found:
            errors.append(f"[X] Quote block with text '{expected_quote}' not found after divider")
        else:
            checks_passed.append(f"[C] Quote block with text '{expected_quote}' found after divider")
    
        # 9. Verify all heading3 blocks have emoji prefix pattern
        heading3_blocks = [b for b in page_blocks_sorted if b.get("type") == "heading3"]
    
        # Simple emoji detection - check if first character is an emoji or contains common emoji
        emoji_pattern = re.compile(
            "["
            "\U0001F300-\U0001F9FF"  # Miscellaneous Symbols and Pictographs, Emoticons, etc.
            "\U00002702-\U000027B0"  # Dingbats
            "\U0001F600-\U0001F64F"  # Emoticons
            "\U0001F680-\U0001F6FF"  # Transport and Map Symbols
            "\U0001F1E0-\U0001F1FF"  # Flags
            "\U00002600-\U000026FF"  # Misc symbols
            "\U0001FA00-\U0001FA6F"  # Chess Symbols
            "\U0001FA70-\U0001FAFF"  # Symbols and Pictographs Extended-A
            "]"
        )
    
        for block in heading3_blocks:
            content = block.get("content", "")
            if not emoji_pattern.search(content):
                errors.append(f"[X] heading3 '{content}' does not have an emoji prefix. All heading3 blocks must use emoji prefix pattern.")
            else:
                checks_passed.append(f"[C] heading3 '{content}' has an emoji prefix. All heading3 blocks must use emoji prefix pattern.")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

    # -----------------------------------------------------------------------------
    # Task: company-handbook-policy-update
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_company_handbook_policy_update(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Company Handbook Policy Update task.
    
    Goal: Reorganize content and add new policy information in the Company Handbook page.
    
    Validation steps:
    1. Find Company Handbook page (page-16)
    2. Verify table of contents exists at the beginning (after main heading) with bulleted 
       lists linking to major sections (Our Values, Benefits, Work Policies)
    3. Verify Benefits section appears immediately after Our Values section
    4. Verify Equipment Policy heading_3 exists between Remote Work and Time Off with 3 numbered items
    5. Verify gray callout appears after Time Off subsection with PTO approval note
    
    Weights: All checks must pass (binary 0/1).
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    
    # 1. Find Company Handbook page
    try:
        handbook_page = _find_page_by_title(final_state_backend, "Company Handbook")
        if not handbook_page:
            errors.append("[X] Company Handbook page not found")
        else:
            checks_passed.append("[C] Company Handbook page found")
    
        page_id = handbook_page.get("_id")
        page_blocks = _get_blocks_for_page(final_state_backend, page_id)
    
        if not page_blocks:
            errors.append("[X] No blocks found on Company Handbook page")
        else:
            checks_passed.append("[C] blocks found on Company Handbook page")
    
        # Sort blocks by order
        page_blocks_sorted = sorted(page_blocks, key=lambda b: b.get("order", 0))
    
        # Find key positions
        main_heading_idx = None
        our_values_idx = None
        benefits_idx = None
        work_policies_idx = None
        remote_work_idx = None
        equipment_policy_idx = None
        time_off_idx = None
    
        for idx, block in enumerate(page_blocks_sorted):
            block_type = block.get("type", "")
            content = block.get("content", "").lower()
        
            if block_type == "heading1" and "company handbook" in content:
                main_heading_idx = idx
            elif block_type == "heading2" and "our values" in content:
                our_values_idx = idx
            elif block_type == "heading2" and "benefits" in content:
                benefits_idx = idx
            elif block_type == "heading2" and "work policies" in content:
                work_policies_idx = idx
            elif block_type == "heading3" and "remote work" in content:
                remote_work_idx = idx
            elif block_type == "heading3" and "equipment policy" in content:
                equipment_policy_idx = idx
            elif block_type == "heading3" and "time off" in content:
                time_off_idx = idx
    
        # Validation 1: Main heading must exist
        if main_heading_idx is None:
            errors.append("[X] Main heading 'Company Handbook' not found")
        else:
            checks_passed.append("[C] Main heading 'Company Handbook' found")
    
        # Validation 2: Check table of contents exists after main heading
        # Look for bulleted list items that reference major sections
        toc_bullets_found = []
        expected_toc_sections = ["our values", "benefits", "work policies"]
    
        # Search for bulleted list items between main heading and first major section
        first_h2_idx = None
        for idx, block in enumerate(page_blocks_sorted):
            if block.get("type") == "heading2":
                first_h2_idx = idx
                break
    
        if first_h2_idx is None:
            errors.append("[X] No heading2 blocks found on the page")
        else:
            checks_passed.append("[C] heading2 blocks found on the page")
    
        # Look for bulleted list items between main heading and first h2
        for idx in range(main_heading_idx + 1, first_h2_idx):
            block = page_blocks_sorted[idx]
            if block.get("type") == "bulletedList":
                content = block.get("content", "").lower()
                toc_bullets_found.append(content)
    
        if not toc_bullets_found:
            errors.append("[X] No table of contents found after main heading. Expected bulleted lists linking to major sections.")
        else:
            checks_passed.append("[C] table of contents found after main heading. Expected bulleted lists linking to major sections.")
    
        # Check that TOC contains references to major sections
        sections_found_in_toc = 0
        for section in expected_toc_sections:
            for bullet in toc_bullets_found:
                if section in bullet:
                    sections_found_in_toc += 1
                    break
    
        if sections_found_in_toc < len(expected_toc_sections):
            errors.append(f"[X] Table of contents incomplete. Expected references to {expected_toc_sections}, found references to {sections_found_in_toc} sections. TOC bullets: {toc_bullets_found}")
        else:
            checks_passed.append(f"[C] Table of contents incomplete. Expected references to {expected_toc_sections}, found references to {sections_found_in_toc} sections. TOC bullets: {toc_bullets_found}")
    
        # Validation 3: Verify Benefits section appears immediately after Our Values section
        if our_values_idx is None:
            errors.append("[X] heading_2 'Our Values' not found")
        else:
            checks_passed.append("[C] heading_2 'Our Values' found")
    
        if benefits_idx is None:
            errors.append("[X] heading_2 'Benefits' not found")
        else:
            checks_passed.append("[C] heading_2 'Benefits' found")
    
        # Find the next heading2 after Our Values
        next_h2_after_values = None
        for idx in range(our_values_idx + 1, len(page_blocks_sorted)):
            block = page_blocks_sorted[idx]
            if block.get("type") == "heading2":
                next_h2_after_values = idx
                break
    
        if next_h2_after_values != benefits_idx:
            errors.append(f"[X] Benefits section must appear immediately after Our Values. Found heading2 at index {next_h2_after_values}, expected Benefits at {benefits_idx}")
        else:
            checks_passed.append(f"[C] Benefits section must appear immediately after Our Values. Found heading2 at index {next_h2_after_values}, expected Benefits at {benefits_idx}")
    
        # Validation 4: Verify Equipment Policy exists between Remote Work and Time Off
        if work_policies_idx is None:
            errors.append("[X] heading_2 'Work Policies' not found")
        else:
            checks_passed.append("[C] heading_2 'Work Policies' found")
    
        if remote_work_idx is None:
            errors.append("[X] heading_3 'Remote Work' not found")
        else:
            checks_passed.append("[C] heading_3 'Remote Work' found")
    
        if time_off_idx is None:
            errors.append("[X] heading_3 'Time Off' not found")
        else:
            checks_passed.append("[C] heading_3 'Time Off' found")
    
        if equipment_policy_idx is None:
            errors.append("[X] heading_3 '💻 Equipment Policy' not found")
        else:
            checks_passed.append("[C] heading_3 '💻 Equipment Policy' found")
    
        # Check Equipment Policy is between Remote Work and Time Off
        if not (remote_work_idx < equipment_policy_idx < time_off_idx):
            errors.append(f"[X] Equipment Policy (idx {equipment_policy_idx}) must be between Remote Work (idx {remote_work_idx}) and Time Off (idx {time_off_idx})")
        else:
            checks_passed.append(f"[C] Equipment Policy (idx {equipment_policy_idx}) must be between Remote Work (idx {remote_work_idx}) and Time Off (idx {time_off_idx})")
    
        # Check for 3 numbered list items after Equipment Policy
        numbered_items = []
        expected_items = [
            "all employees receive a laptop and necessary peripherals",
            "home office stipend of $1,000 per year",
            "equipment refresh cycle every 3 years"
        ]
    
        for idx in range(equipment_policy_idx + 1, time_off_idx):
            block = page_blocks_sorted[idx]
            if block.get("type") == "numberedList":
                numbered_items.append(block.get("content", "").lower())
            elif block.get("type") in ["heading3", "heading2"]:
                break
    
        if len(numbered_items) < 3:
            errors.append(f"[X] Expected 3 numbered list items under Equipment Policy, found {len(numbered_items)}")
        else:
            checks_passed.append(f"[C] Found 3 numbered list items under Equipment Policy as expected")
    
        # Verify content of numbered items
        for expected in expected_items:
            found = False
            for item in numbered_items:
                if expected in item:
                    found = True
                    break
            if not found:
                errors.append(f"[X] Missing numbered list item containing: '{expected}'. Found items: {numbered_items}")
            else:
                checks_passed.append(f"[C] has numbered list item containing: '{expected}'. Found items: {numbered_items}")
    
        # Validation 5: Verify gray callout after Time Off subsection
        # Look for gray callout after Time Off subsection
        gray_callout_found = False
        expected_callout_text = "unlimited pto policy requires manager approval for absences longer than 2 weeks"
    
        for idx in range(time_off_idx + 1, len(page_blocks_sorted)):
            block = page_blocks_sorted[idx]
            if block.get("type") == "callout":
                props = block.get("properties", {})
                bg_color = props.get("backgroundColor", "")
                content = block.get("content", "").lower()
            
                if "gray" in bg_color.lower() and expected_callout_text in content:
                    gray_callout_found = True
                    break
                elif expected_callout_text in content:
                    # Check if content matches even if bg color check is different
                    gray_callout_found = True
                    break
    
        if not gray_callout_found:
            errors.append(f"[X] Gray callout with text about unlimited PTO policy not found after Time Off subsection. Expected text containing: '{expected_callout_text}'")
        else:
            checks_passed.append(f"[C] Gray callout with text about unlimited PTO policy found after Time Off subsection. Expected text containing: '{expected_callout_text}'")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

    # -----------------------------------------------------------------------------
    # Task: project-documentation-index
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_project_documentation_index(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate comprehensive child page index for Project Documentation page.
    
    Goal: Navigate to 'Project Documentation' and create a comprehensive child page index
    with hierarchical numbering, block counts, statistics callout, and bookmark to largest page.
    
    Validation steps (ordered):
    1. Find 'Project Documentation' page (page-22)
    2. Get all blocks for the page and verify heading_2 '📚 Documentation Structure' is first
    3. Gather all descendant pages and their block counts
    4. Verify hierarchical numbered list with correct format '[Number] [Icon] [Title] ([Block Count] blocks)'
    5. Verify callout with orange_background, icon '📈', and correct totals text
    6. Verify bookmark with url 'https://docs.internal/largest' and caption referencing page with most blocks
    
    Expected hierarchy:
    1. 🏗️ Architecture (1 blocks)
       1.1. 🎨 Frontend Architecture (0 blocks)
            1.1.1. 🧩 Component Library (0 blocks)
            1.1.2. 🔄 State Management (0 blocks)
       1.2. ⚙️ Backend Architecture (0 blocks)
            1.2.1. 🔌 API Design Patterns (0 blocks)
    2. 🚀 Deployment Guide (0 blocks)
       2.1. 🔄 CI/CD Pipeline (0 blocks)
    
    Weights: All-or-nothing (1.0 if all pass, 0.0 otherwise)
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    
    # 1. Find the Project Documentation page
    try:
        project_doc_page = _find_page_by_title(final_state_backend, "Project Documentation")
        if not project_doc_page:
            errors.append("[X] Project Documentation page not found")
        else:
            checks_passed.append("[C] Project Documentation page found")
    
        page_id = project_doc_page.get("_id")
        page_blocks = _get_blocks_for_page(final_state_backend, page_id)
    
        if not page_blocks:
            errors.append("[X] No blocks found on Project Documentation page")
        else:
            checks_passed.append("[C] blocks found on Project Documentation page")
    
        # 2. Sort blocks by order and verify heading_2 '📚 Documentation Structure' is first
        page_blocks_sorted = sorted(page_blocks, key=lambda b: b.get("order", 0))
    
        first_block = page_blocks_sorted[0]
        first_block_type = first_block.get("type", "")
        first_block_content = first_block.get("content", "")
    
        if first_block_type not in ["heading2", "heading_2"]:
            errors.append(f"[X] First block should be heading_2, found '{first_block_type}'")
        else:
            checks_passed.append(f"[C] First block should be heading_2, found '{first_block_type}'")
    
        if "📚" not in first_block_content or "documentation structure" not in first_block_content.lower():
            errors.append(f"[X] First heading_2 should be '📚 Documentation Structure', found '{first_block_content}'")
        else:
            checks_passed.append(f"[C] First heading_2 should be '📚 Documentation Structure', found '{first_block_content}'")
    
        # 3. Build the expected descendant hierarchy and calculate block counts
        def get_descendants_with_depth(parent_id: str, depth: int = 0) -> List[Dict[str, Any]]:
            """Recursively get all descendants with their depth level."""
            result = []
            children = _get_child_pages(final_state_backend, parent_id)
            for child in children:
                child_blocks = _get_blocks_for_page(final_state_backend, child.get("_id"))
                block_count = len(child_blocks)
                result.append({
                    "page": child,
                    "depth": depth,
                    "block_count": block_count
                })
                result.extend(get_descendants_with_depth(child.get("_id"), depth + 1))
            return result
    
        descendants = get_descendants_with_depth(page_id)
    
        if not descendants:
            errors.append("[X] No descendant pages found under Project Documentation")
        else:
            checks_passed.append("[C] descendant pages found under Project Documentation")
    
        # Calculate totals
        total_pages = len(descendants)
        total_blocks = sum(d["block_count"] for d in descendants)
    
        # Find page with most blocks
        max_blocks_page = max(descendants, key=lambda d: d["block_count"])
        max_blocks_title = max_blocks_page["page"].get("title", "")
    
        # 4. Verify numbered list entries exist with correct format
        # Look for numbered list items after the heading
        numbered_list_items = [b for b in page_blocks_sorted if b.get("type") in ["numberedList", "numbered_list"]]
    
        if len(numbered_list_items) < total_pages:
            errors.append(f"[X] Expected at least {total_pages} numbered list items for descendant pages, found {len(numbered_list_items)}")
        else:
            checks_passed.append(f"[C] Expected at least {total_pages} numbered list items for descendant pages, found {len(numbered_list_items)}")
    
        # Verify each descendant page has an entry in the numbered list
        # Check that entries contain: number pattern, icon, title, and block count
        for desc in descendants:
            page_title = desc["page"].get("title", "")
            page_icon = desc["page"].get("icon", "")
            block_count = desc["block_count"]
        
            entry_found = False
            for item in numbered_list_items:
                content = item.get("content", "")
                content_lower = content.lower()
            
                # Check if this numbered list item contains the page info
                # Format: '[Number] [Icon] [Title] ([Block Count] blocks)'
                if page_title.lower() in content_lower:
                    # Verify icon is present
                    if page_icon and page_icon in content:
                        # Verify block count format
                        if f"{block_count} block" in content_lower or f"({block_count} block" in content_lower:
                            entry_found = True
                            break
        
            if not entry_found:
                errors.append(f"[X] Missing or incorrectly formatted numbered list entry for '{page_title}' with icon '{page_icon}' and {block_count} blocks")
            else:
                checks_passed.append(f"[C] has or incorrectly formatted numbered list entry for '{page_title}' with icon '{page_icon}' and {block_count} blocks")
    
        # 5. Verify callout with orange_background, icon '📈', and correct totals
        callout_found = False
        for block in page_blocks_sorted:
            if block.get("type") == "callout":
                properties = block.get("properties", {})
                background = properties.get("backgroundColor", properties.get("background", ""))
                icon = properties.get("icon", "")
                content = block.get("content", "")
                content_lower = content.lower()
            
                # Check for orange background
                is_orange = "orange" in background.lower() if background else False
                # Check for 📈 icon
                has_icon = "📈" in icon
                # Check for totals text
                has_total_pages = f"total pages: {total_pages}" in content_lower or f"total pages:{total_pages}" in content_lower
                has_total_blocks = f"total blocks across all pages: {total_blocks}" in content_lower or f"total blocks:{total_blocks}" in content_lower
            
                if is_orange and has_icon:
                    if has_total_pages and has_total_blocks:
                        callout_found = True
                        break
                    else:
                        # Found the callout but totals might be wrong
                        if not has_total_pages:
                            errors.append(f"[X] Callout found but missing correct 'Total pages: {total_pages}'. Content: '{content}'")
                        else:
                            checks_passed.append(f"[C] Callout found but has correct 'Total pages: {total_pages}'. Content: '{content}'")
                        if not has_total_blocks:
                            errors.append(f"[X] Callout found but missing correct 'Total blocks across all pages: {total_blocks}'. Content: '{content}'")
                        else:
                            checks_passed.append(f"[C] Callout found but has correct 'Total blocks across all pages: {total_blocks}'. Content: '{content}'")
    
        if not callout_found:
            errors.append(f"[X] Callout with orange_background, 📈 icon, and totals (Total pages: {total_pages} | Total blocks across all pages: {total_blocks}) not found")
        else:
            checks_passed.append(f"[C] Callout with orange_background, 📈 icon, and totals (Total pages: {total_pages} | Total blocks across all pages: {total_blocks}) found")
    
        # 6. Verify bookmark with url and caption referencing largest page
        bookmark_found = False
        for block in page_blocks_sorted:
            if block.get("type") == "bookmark":
                properties = block.get("properties", {})
                url = properties.get("url", "")
                caption = properties.get("caption", block.get("content", ""))
            
                # Check for correct URL
                has_correct_url = "https://docs.internal/largest" in url
                # Check caption references the page with most blocks
                has_correct_caption = max_blocks_title.lower() in caption.lower() and "view most comprehensive section" in caption.lower()
            
                if has_correct_url:
                    if has_correct_caption:
                        bookmark_found = True
                        break
                    else:
                        errors.append(f"[X] Bookmark found with correct URL but caption should reference '{max_blocks_title}'. Caption: '{caption}'")
    
        if not bookmark_found:
            errors.append(f"[X] Bookmark with url 'https://docs.internal/largest' and caption 'View most comprehensive section: {max_blocks_title}' not found")
        else:
            checks_passed.append(f"[C] Bookmark with url 'https://docs.internal/largest' and caption 'View most comprehensive section: {max_blocks_title}' found")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

    # -----------------------------------------------------------------------------
    # Task: engineering-wiki-advanced-content-analysis
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_engineering_wiki_advanced_content_analysis(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate advanced content analysis and update on Engineering Wiki page.
    
    Goal: Navigate to Engineering Wiki, count bullet/numbered lists, insert code block
    and callout in specific positions, and add statistics section at the end.
    
    Validation steps (ordered):
    1. Find the 'Engineering Wiki' page (page-4)
    2. Get all blocks sorted by order
    3. Count original bulletedList blocks (should be 3)
    4. Count original numberedList blocks (should be 3)
    5. Find 'Environment Variables' heading_3 and its following paragraph
    6. Verify bash code block exists BETWEEN heading_3 and paragraph with exact content
    7. Verify red callout with 🔒 icon exists AFTER the paragraph
    8. Verify divider at the end of page
    9. Verify heading_2 '📊 Page Statistics' after divider
    10. Verify paragraph with correct counts: 'This wiki page contains [X] bullet points and [Y] numbered steps for easy reference.'
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    
    # 1. Find the Engineering Wiki page
    try:
        engineering_wiki = _find_page_by_title(final_state_backend, "Engineering Wiki")
        if not engineering_wiki:
            errors.append("[X] Engineering Wiki page not found")
        else:
            checks_passed.append("[C] Engineering Wiki page found")
    
        page_id = engineering_wiki.get("_id")
        page_blocks = _get_blocks_for_page(final_state_backend, page_id)
    
        if not page_blocks:
            errors.append("[X] No blocks found on Engineering Wiki page")
        else:
            checks_passed.append("[C] blocks found on Engineering Wiki page")
    
        # Sort blocks by order
        page_blocks_sorted = sorted(page_blocks, key=lambda b: b.get("order", 0))
    
        # 2. Count bulletedList blocks - the original page has exactly 3
        # Original IDs: block-4-4, block-4-5, block-4-6 (Tech Stack items)
        bulleted_blocks = [b for b in page_blocks_sorted if b.get("type") in ["bulletedList", "bulleted_list", "bulletedListItem", "bulleted_list_item"]]
    
        # The original page has exactly 3 bulleted list items
        original_bullet_count = 3
    
        # 3. Count numberedList blocks - the original page has exactly 3
        # Original IDs: block-4-8, block-4-9, block-4-10 (Development Setup items)
        numbered_blocks = [b for b in page_blocks_sorted if b.get("type") in ["numberedList", "numbered_list", "numberedListItem", "numbered_list_item"]]
    
        # The original page has exactly 3 numbered list items
        original_numbered_count = 3
    
        # 4. Find 'Environment Variables' heading_3
        env_vars_heading_idx = None
        env_vars_heading = None
        for idx, block in enumerate(page_blocks_sorted):
            content = block.get("content", "")
            block_type = block.get("type", "")
            if block_type in ["heading3", "heading_3"] and "environment variables" in content.lower():
                env_vars_heading_idx = idx
                env_vars_heading = block
                break
    
        if env_vars_heading_idx is None:
            errors.append("[X] heading_3 'Environment Variables' not found on Engineering Wiki page")
        else:
            checks_passed.append("[C] heading_3 'Environment Variables' found on Engineering Wiki page")
    
        # 5. Find the original paragraph after Environment Variables (Copy .env.example to .env...)
        original_paragraph_idx = None
        original_paragraph = None
        for idx, block in enumerate(page_blocks_sorted):
            content = block.get("content", "")
            block_type = block.get("type", "")
            if block_type == "paragraph" and ".env.example" in content and ".env" in content:
                original_paragraph_idx = idx
                original_paragraph = block
                break
    
        if original_paragraph_idx is None:
            errors.append("[X] Original paragraph about .env.example not found on Engineering Wiki page")
        else:
            checks_passed.append("[C] Original paragraph about .env.example found on Engineering Wiki page")
    
        env_vars_order = env_vars_heading.get("order", 0)
        original_para_order = original_paragraph.get("order", 0)
    
        # 6. Verify bash code block exists BETWEEN heading_3 and original paragraph
        code_block = None
        for block in page_blocks_sorted:
            block_type = block.get("type", "")
            block_order = block.get("order", 0)
            if block_type == "code" and block_order > env_vars_order and block_order < original_para_order:
                code_block = block
                break
    
        if code_block is None:
            errors.append(f"[X] Code block not found between 'Environment Variables' heading (order {env_vars_order}) and its paragraph (order {original_para_order})")
        else:
            checks_passed.append(f"[C] Code block found between 'Environment Variables' heading (order {env_vars_order}) and its paragraph (order {original_para_order})")
    
        # Verify code block properties
        code_props = code_block.get("properties", {})
        code_language = code_props.get("language", "").lower()
        if code_language != "bash":
            errors.append(f"[X] Code block should have language 'bash', got '{code_language}'")
        else:
            checks_passed.append(f"[C] Code block should have language 'bash', got '{code_language}'")
    
        # Verify code block content
        code_content = code_block.get("content", "")
        required_env_vars = [
            "DATABASE_URL=mongodb://localhost:27017/myapp",
            "REDIS_URL=redis://localhost:6379",
            "JWT_SECRET=your-secret-key-here"
        ]
    
        for env_var in required_env_vars:
            if env_var not in code_content:
                errors.append(f"[X] Code block missing required environment variable: '{env_var}'")
            else:
                checks_passed.append(f"[C] Code block has required environment variable: '{env_var}'")
    
        if "# Required environment variables" not in code_content:
            errors.append(f"[X] Code block missing comment '# Required environment variables'")
        else:
            checks_passed.append(f"[C] Code block has comment '# Required environment variables'")
    
        # 7. Verify red callout with 🔒 icon exists AFTER the original paragraph
        red_callout = None
        for block in page_blocks_sorted:
            block_type = block.get("type", "")
            block_order = block.get("order", 0)
            if block_type == "callout" and block_order > original_para_order:
                props = block.get("properties", {})
                bg_color = props.get("backgroundColor", "").lower()
                icon = props.get("icon", "")
                content = block.get("content", "")
            
                if "red" in bg_color and "🔒" in icon:
                    red_callout = block
                    break
    
        if red_callout is None:
            errors.append("[X] Red callout with 🔒 icon not found after the Environment Variables paragraph")
        else:
            checks_passed.append("[C] Red callout with 🔒 icon found after the Environment Variables paragraph")
    
        # Verify callout content
        callout_content = red_callout.get("content", "")
        if "Never commit .env files to version control" not in callout_content:
            errors.append(f"[X] Callout missing text 'Never commit .env files to version control'. Got: '{callout_content}'")
        else:
            checks_passed.append(f"[C] Callout has text 'Never commit .env files to version control'. Got: '{callout_content}'")
        if ".env.example as a template" not in callout_content:
            errors.append(f"[X] Callout missing text '.env.example as a template'. Got: '{callout_content}'")
        else:
            checks_passed.append(f"[C] Callout has text '.env.example as a template'. Got: '{callout_content}'")
    
        red_callout_order = red_callout.get("order", 0)
    
        # 8. Verify divider at the end of page (after the red callout)
        divider_block = None
        for block in page_blocks_sorted:
            block_type = block.get("type", "")
            block_order = block.get("order", 0)
            if block_type == "divider" and block_order > red_callout_order:
                divider_block = block
                break
    
        if divider_block is None:
            errors.append("[X] Divider not found at the end of the page")
        else:
            checks_passed.append("[C] Divider found at the end of the page")
    
        divider_order = divider_block.get("order", 0)
    
        # 9. Verify heading_2 '📊 Page Statistics' after divider
        stats_heading = None
        for block in page_blocks_sorted:
            block_type = block.get("type", "")
            block_order = block.get("order", 0)
            content = block.get("content", "")
            if block_type in ["heading2", "heading_2"] and block_order > divider_order:
                if "page statistics" in content.lower() and "📊" in content:
                    stats_heading = block
                    break
    
        if stats_heading is None:
            errors.append("[X] heading_2 '📊 Page Statistics' not found after divider")
        else:
            checks_passed.append("[C] heading_2 '📊 Page Statistics' found after divider")
    
        stats_heading_order = stats_heading.get("order", 0)
    
        # 10. Verify paragraph with correct counts
        stats_paragraph = None
        for block in page_blocks_sorted:
            block_type = block.get("type", "")
            block_order = block.get("order", 0)
            if block_type == "paragraph" and block_order > stats_heading_order:
                stats_paragraph = block
                break
    
        if stats_paragraph is None:
            errors.append("[X] Paragraph not found after '📊 Page Statistics' heading")
        else:
            checks_passed.append("[C] Paragraph found after '📊 Page Statistics' heading")
    
        stats_content = stats_paragraph.get("content", "")
    
        # Check for the pattern with correct counts
        # Original counts: 3 bullet points, 3 numbered steps
        expected_bullet_str = str(original_bullet_count)
        expected_numbered_str = str(original_numbered_count)
    
        if "This wiki page contains" not in stats_content:
            errors.append(f"[X] Statistics paragraph missing 'This wiki page contains'. Got: '{stats_content}'")
        else:
            checks_passed.append(f"[C] Statistics paragraph has 'This wiki page contains'. Got: '{stats_content}'")
    
        if "bullet points" not in stats_content.lower():
            errors.append(f"[X] Statistics paragraph missing 'bullet points'. Got: '{stats_content}'")
        else:
            checks_passed.append(f"[C] Statistics paragraph has 'bullet points'. Got: '{stats_content}'")
    
        if "numbered steps" not in stats_content.lower():
            errors.append(f"[X] Statistics paragraph missing 'numbered steps'. Got: '{stats_content}'")
        else:
            checks_passed.append(f"[C] Statistics paragraph has 'numbered steps'. Got: '{stats_content}'")
    
        if "for easy reference" not in stats_content.lower():
            errors.append(f"[X] Statistics paragraph missing 'for easy reference'. Got: '{stats_content}'")
        else:
            checks_passed.append(f"[C] Statistics paragraph has 'for easy reference'. Got: '{stats_content}'")
    
        # Check that the counts are correct (3 bullet points, 3 numbered steps)
        if expected_bullet_str not in stats_content or expected_numbered_str not in stats_content:
            errors.append(f"[X] Statistics paragraph should contain '{expected_bullet_str}' bullet points and '{expected_numbered_str}' numbered steps. Got: '{stats_content}'")
        else:
            checks_passed.append(f"[C] Statistics paragraph should contain '{expected_bullet_str}' bullet points and '{expected_numbered_str}' numbered steps. Got: '{stats_content}'")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

    # -----------------------------------------------------------------------------
    # Task: workspace-analytics-hub
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_workspace_analytics_hub(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Workspace Analytics Hub page creation and content accuracy.
    
    Goal: Create a comprehensive workspace analytics dashboard that:
    1. Exists at workspace root level (no parentId)
    2. Has heading_1 '📊 Workspace Analytics Hub'
    3. Has blue callout with '🔄' icon after title with timestamp and total page count
    4. Has heading_2 '📈 Content Overview' with accurate counts:
       - Favorite pages count
       - Archived pages count
       - Pages with to-do blocks count
    5. Has heading_2 '🎯 Project Status' with Q1 and Q2 completion percentages
    6. Has heading_2 '📝 Meeting Insights' with meeting page count
    
    Validation steps (all-or-nothing):
    1. Find 'Workspace Analytics Hub' page at workspace root
    2. Verify heading_1 with correct title
    3. Verify blue callout with '🔄' icon containing timestamp and total count
    4. Verify heading_2 'Content Overview' section exists
    5. Verify favorite pages count (16)
    6. Verify archived pages count (6)
    7. Verify pages with todos count (7)
    8. Verify heading_2 'Project Status' section exists
    9. Verify Q1 Goals completion percentage (66.7% or ~67%)
    10. Verify Q2 Goals completion percentage (0%)
    11. Verify heading_2 'Meeting Insights' section exists
    12. Verify meeting pages count (2 pages under Meeting Notes)
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    
    # 1. Find 'Workspace Analytics Hub' page at workspace root level
    try:
        analytics_result = final_state_backend.query({
            "collection": "pages",
            "filter": {
                "title": {"$regex": "Workspace Analytics Hub", "$options": "i"},
                "parentId": None,
                "workspaceId": "workspace-1"
            }
        })
        analytics_hub = analytics_result[0] if isinstance(analytics_result, list) and analytics_result else None
        if not analytics_hub:
            errors.append("[X] Workspace Analytics Hub page not found at workspace root level")
        else:
            checks_passed.append("[C] Workspace Analytics Hub page found at workspace root level")

        page_id = analytics_hub.get("_id")
        page_blocks = _get_blocks_for_page(final_state_backend, page_id)
    
        if not page_blocks:
            errors.append("[X] Workspace Analytics Hub page has no blocks")
        else:
            checks_passed.append("[C] Workspace Analytics Hub page has blocks")
    
        # Sort blocks by order
        page_blocks_sorted = sorted(page_blocks, key=lambda b: b.get("order", 0))
    
        # 2. Verify heading_1 '📊 Workspace Analytics Hub' exists
        has_main_heading = False
        for block in page_blocks_sorted:
            if block.get("type") == "heading1":
                content = block.get("content", "").lower()
                if "workspace analytics hub" in content:
                    has_main_heading = True
                    break
    
        if not has_main_heading:
            errors.append("[X] Missing heading_1 with 'Workspace Analytics Hub'")
        else:
            checks_passed.append("[C] has heading_1 with 'Workspace Analytics Hub'")
    
        # 3. Verify blue callout with '🔄' icon after the title
        # The callout should contain timestamp and total page count
        has_refresh_callout = False
        for block in page_blocks_sorted:
            if block.get("type") == "callout":
                props = block.get("properties", {})
                bg_color = props.get("backgroundColor", "").lower()
                icon = props.get("icon", "")
                content = block.get("content", "").lower()

                # Check for blue background and refresh icon
                if "blue" in bg_color and icon == "🔄":
                    # Check content mentions "refreshed" or "dashboard" and contains a number (page count)
                    if "refresh" in content or "dashboard" in content:
                        # Verify some number is mentioned (representing page count)
                        import re
                        if re.search(r'\d+', block.get("content", "")):
                            has_refresh_callout = True
                            break

        if not has_refresh_callout:
            errors.append("[X] Missing blue callout with '🔄' icon containing refresh timestamp and total page count")
        else:
            checks_passed.append("[C] has blue callout with '🔄' icon containing refresh timestamp and total page count")
    
        # 4. Verify heading_2 '📈 Content Overview' exists
        has_content_overview = False
        for block in page_blocks_sorted:
            if block.get("type") == "heading2":
                content = block.get("content", "").lower()
                if "content overview" in content:
                    has_content_overview = True
                    break
    
        if not has_content_overview:
            errors.append("[X] Missing heading_2 'Content Overview'")
        else:
            checks_passed.append("[C] has heading_2 'Content Overview'")
    
        # Calculate expected counts from backend data
        favorite_pages_result = final_state_backend.query({"collection": "pages", "filter": {"isFavorite": True}})
        favorite_pages_count = len(favorite_pages_result) if isinstance(favorite_pages_result, list) else 0
        archived_pages_result = final_state_backend.query({"collection": "pages", "filter": {"isArchived": True}})
        archived_pages_count = len(archived_pages_result) if isinstance(archived_pages_result, list) else 0
    
        # Count pages with todo blocks
        todo_blocks_result = final_state_backend.query({"collection": "blocks", "filter": {"type": "todo"}})
        todo_blocks = todo_blocks_result if isinstance(todo_blocks_result, list) else []
        pages_with_todos = set()
        for block in todo_blocks:
            pages_with_todos.add(block.get("pageId"))
        pages_with_todos_count = len(pages_with_todos)
    
        # 5-7. Verify counts are mentioned in the page content
        all_content = " ".join([b.get("content", "") for b in page_blocks_sorted]).lower()
    
        # Check for favorite pages count
        if str(favorite_pages_count) not in all_content and "favorite" not in all_content:
            errors.append(f"[X] Content should mention favorite pages count ({favorite_pages_count})")
        else:
            checks_passed.append(f"[C] Content should mention favorite pages count ({favorite_pages_count})")
    
        # Check for archived pages count
        if str(archived_pages_count) not in all_content:
            errors.append(f"[X] Content should mention archived pages count ({archived_pages_count})")
        else:
            checks_passed.append(f"[C] Content should mention archived pages count ({archived_pages_count})")
    
        # Check for pages with todos count
        if str(pages_with_todos_count) not in all_content:
            errors.append(f"[X] Content should mention pages with to-do blocks count ({pages_with_todos_count})")
        else:
            checks_passed.append(f"[C] Content should mention pages with to-do blocks count ({pages_with_todos_count})")
    
        # 8. Verify heading_2 '🎯 Project Status' exists
        has_project_status = False
        for block in page_blocks_sorted:
            if block.get("type") == "heading2":
                content = block.get("content", "").lower()
                if "project status" in content:
                    has_project_status = True
                    break
    
        if not has_project_status:
            errors.append("[X] Missing heading_2 'Project Status'")
        else:
            checks_passed.append("[C] has heading_2 'Project Status'")
    
        # 9-10. Calculate and verify Q1/Q2 completion percentages
        project_roadmap = _find_page_by_title(final_state_backend, "Project Roadmap")
        if not project_roadmap:
            errors.append("[X] Project Roadmap page not found for calculating completion rates")
        else:
            checks_passed.append("[C] Project Roadmap page found for calculating completion rates")
    
        q1_goals = _find_page_by_title_pattern_and_parent(final_state_backend, "Q1 Goals", project_roadmap.get("_id"))
        q2_goals = _find_page_by_title_pattern_and_parent(final_state_backend, "Q2 Goals", project_roadmap.get("_id"))
    
        if not q1_goals:
            errors.append("[X] Q1 Goals page not found")
        else:
            checks_passed.append("[C] Q1 Goals page found")
        if not q2_goals:
            errors.append("[X] Q2 Goals page not found")
        else:
            checks_passed.append("[C] Q2 Goals page found")
    
        # Count Q1 todos
        q1_blocks = _get_blocks_for_page(final_state_backend, q1_goals.get("_id"))
        q1_todos = [b for b in q1_blocks if b.get("type") == "todo"]
        q1_checked = len([b for b in q1_todos if b.get("properties", {}).get("checked")])
        q1_total = len(q1_todos)
        q1_percentage = round((q1_checked / q1_total * 100) if q1_total > 0 else 0, 1)
    
        # Count Q2 todos
        q2_blocks = _get_blocks_for_page(final_state_backend, q2_goals.get("_id"))
        q2_todos = [b for b in q2_blocks if b.get("type") == "todo"]
        q2_checked = len([b for b in q2_todos if b.get("properties", {}).get("checked")])
        q2_total = len(q2_todos)
        q2_percentage = round((q2_checked / q2_total * 100) if q2_total > 0 else 0, 1)
    
        # Check that Q1 percentage is mentioned (should be ~66.7%)
        q1_mentioned = False
        for pct in ["66.7", "66.67", "67", "66"]:
            if pct in all_content:
                q1_mentioned = True
                break
    
        if not q1_mentioned and "q1" in all_content:
            q1_mentioned = True
    
        if not q1_mentioned:
            errors.append(f"[X] Content should mention Q1 Goals completion percentage (~{q1_percentage}%)")
        else:
            checks_passed.append(f"[C] Content should mention Q1 Goals completion percentage (~{q1_percentage}%)")
    
        # Check Q2 percentage (should be 0%)
        q2_mentioned = False
        if "0%" in all_content or "0 %" in all_content or ("q2" in all_content and "0" in all_content):
            q2_mentioned = True
    
        if not q2_mentioned:
            errors.append(f"[X] Content should mention Q2 Goals completion percentage ({q2_percentage}%)")
        else:
            checks_passed.append(f"[C] Content should mention Q2 Goals completion percentage ({q2_percentage}%)")
    
        # 11. Verify heading_2 '📝 Meeting Insights' exists
        has_meeting_insights = False
        for block in page_blocks_sorted:
            if block.get("type") == "heading2":
                content = block.get("content", "").lower()
                if "meeting" in content:
                    has_meeting_insights = True
                    break
    
        if not has_meeting_insights:
            errors.append("[X] Missing heading_2 'Meeting Insights'")
        else:
            checks_passed.append("[C] has heading_2 'Meeting Insights'")
    
        # 12. Verify meeting pages count
        meeting_notes = _find_page_by_title(final_state_backend, "Meeting Notes")
        if not meeting_notes:
            errors.append("[X] Meeting Notes page not found")
        else:
            checks_passed.append("[C] Meeting Notes page found")
    
        meeting_children = _get_child_pages(final_state_backend, meeting_notes.get("_id"))
        meeting_count = len(meeting_children)
    
        if str(meeting_count) not in all_content:
            errors.append(f"[X] Content should mention meeting pages count ({meeting_count})")
        else:
            checks_passed.append(f"[C] Content should mention meeting pages count ({meeting_count})")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

    # -----------------------------------------------------------------------------
    # Task: external-resources-link-organization
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_external_resources_links_organization(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate comprehensive link organization system on External Resources & Links page.
    
    Goal: Create a structured link organization system on the External Resources & Links page with:
    1. heading1 '🔗 External Resources & Links'
    2. heading2 '📚 Documentation Links'
    3. Three bookmark blocks with exact URLs and captions (MDN, Stack Overflow, GitHub)
    4. Divider separating sections
    5. heading2 '🛠️ Development Tools'
    6. Two bookmark blocks with exact URLs and captions (VS Code, Postman)
    7. Blue callout with 💡 icon containing current date and #dev-resources channel reference
    
    Validation steps (all-or-nothing):
    1. Find 'External Resources & Links' page (page-48)
    2. Verify heading1 with 🔗 emoji exists
    3. Verify heading2 '📚 Documentation Links' exists
    4. Verify three bookmark blocks with exact URLs and captions in order
    5. Verify divider separates sections
    6. Verify heading2 '🛠️ Development Tools' exists
    7. Verify two bookmark blocks with exact URLs and captions
    8. Verify blue callout with 💡 icon and correct content
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    
    # 1. Find 'External Resources & Links' page
    try:
        resources_result = final_state_backend.query({
            "collection": "pages",
            "filter": {"_id": "page-48"}
        })
        resources_page = resources_result[0] if isinstance(resources_result, list) and resources_result else None
        if not resources_page:
            errors.append("[X] External Resources & Links page (page-48) not found")
        else:
            checks_passed.append("[C] External Resources & Links page (page-48) found")

        page_id = resources_page.get("_id")
        page_blocks = _get_blocks_for_page(final_state_backend, page_id)
    
        if not page_blocks:
            errors.append("[X] External Resources & Links page has no blocks")
        else:
            checks_passed.append("[C] External Resources & Links page has blocks")
    
        # Sort blocks by order
        page_blocks_sorted = sorted(page_blocks, key=lambda b: b.get("order", 0))
    
        # 2. Verify heading1 with 🔗 emoji exists
        heading1_block = None
        for block in page_blocks_sorted:
            if block.get("type") == "heading1":
                content = block.get("content", "")
                if "🔗" in content and "external resources" in content.lower():
                    heading1_block = block
                    break
    
        if not heading1_block:
            errors.append("[X] Missing heading1 with '🔗 External Resources & Links'")
        else:
            checks_passed.append("[C] has heading1 with '🔗 External Resources & Links'")
    
        heading1_order = heading1_block.get("order", 0)
    
        # 3. Verify heading2 '📚 Documentation Links' exists after heading1
        doc_links_heading = None
        for block in page_blocks_sorted:
            if block.get("type") == "heading2":
                content = block.get("content", "")
                block_order = block.get("order", 0)
                if "📚" in content and "documentation" in content.lower() and block_order > heading1_order:
                    doc_links_heading = block
                    break
    
        if not doc_links_heading:
            errors.append("[X] Missing heading2 '📚 Documentation Links' after heading1")
        else:
            checks_passed.append("[C] has heading2 '📚 Documentation Links' after heading1")
    
        doc_links_order = doc_links_heading.get("order", 0)
    
        # 4. Verify three bookmark blocks with exact URLs after Documentation Links heading
        required_doc_bookmarks = [
            {
                "url": "https://developer.mozilla.org/en-US/",
                "caption": "MDN Web Docs - Comprehensive web development documentation"
            },
            {
                "url": "https://stackoverflow.com/",
                "caption": "Stack Overflow - Programming Q&A community"
            },
            {
                "url": "https://github.com/",
                "caption": "GitHub - Code hosting platform"
            }
        ]
    
        # Find all bookmark blocks after doc_links_heading and before any divider
        doc_bookmarks = []
        for block in page_blocks_sorted:
            block_order = block.get("order", 0)
            if block_order > doc_links_order:
                if block.get("type") == "divider":
                    break  # Stop at divider
                if block.get("type") == "bookmark":
                    doc_bookmarks.append(block)
    
        if len(doc_bookmarks) < 3:
            errors.append(f"[X] Expected at least 3 bookmark blocks under Documentation Links, found {len(doc_bookmarks)}")
        else:
            checks_passed.append(f"[C] Found at least 3 bookmark blocks under Documentation Links ({len(doc_bookmarks)})")
    
        # Verify each required bookmark exists with correct URL and caption
        for i, required in enumerate(required_doc_bookmarks):
            found = False
            for bookmark in doc_bookmarks:
                props = bookmark.get("properties", {})
                bookmark_url = props.get("url", "")
                bookmark_caption = props.get("caption", "")
            
                # Check URL (allow with or without trailing slash)
                url_match = (
                    bookmark_url == required["url"] or
                    bookmark_url.rstrip("/") == required["url"].rstrip("/")
                )
            
                # Check caption (case-insensitive, partial match for key parts)
                caption_lower = bookmark_caption.lower()
                required_caption_lower = required["caption"].lower()
            
                # Extract key identifier from caption (e.g., "MDN Web Docs", "Stack Overflow", "GitHub")
                caption_key_parts = required["caption"].split(" - ")[0].lower()
                caption_match = caption_key_parts in caption_lower or required_caption_lower in caption_lower
            
                if url_match and caption_match:
                    found = True
                    break
        
            if not found:
                errors.append(f"[X] Missing bookmark with URL '{required['url']}' and caption containing '{required['caption'].split(' - ')[0]}'")
            else:
                checks_passed.append(f"[C] has bookmark with URL '{required['url']}' and caption containing '{required['caption'].split(' - ')[0]}'")
    
        # 5. Verify divider exists after documentation bookmarks
        divider_block = None
        last_doc_bookmark_order = max(b.get("order", 0) for b in doc_bookmarks) if doc_bookmarks else doc_links_order
    
        for block in page_blocks_sorted:
            block_order = block.get("order", 0)
            if block.get("type") == "divider" and block_order > last_doc_bookmark_order:
                divider_block = block
                break
    
        if not divider_block:
            errors.append("[X] Missing divider after Documentation Links section")
        else:
            checks_passed.append("[C] has divider after Documentation Links section")
    
        divider_order = divider_block.get("order", 0)
    
        # 6. Verify heading2 '🛠️ Development Tools' exists after divider
        dev_tools_heading = None
        for block in page_blocks_sorted:
            if block.get("type") == "heading2":
                content = block.get("content", "")
                block_order = block.get("order", 0)
                if "🛠️" in content and "development tools" in content.lower() and block_order > divider_order:
                    dev_tools_heading = block
                    break
    
        if not dev_tools_heading:
            errors.append("[X] Missing heading2 '🛠️ Development Tools' after divider")
        else:
            checks_passed.append("[C] has heading2 '🛠️ Development Tools' after divider")
    
        dev_tools_order = dev_tools_heading.get("order", 0)
    
        # 7. Verify two bookmark blocks with exact URLs after Development Tools heading
        required_tool_bookmarks = [
            {
                "url": "https://code.visualstudio.com/",
                "caption": "VS Code - Popular code editor"
            },
            {
                "url": "https://www.postman.com/",
                "caption": "Postman - API development environment"
            }
        ]
    
        # Find all bookmark blocks after dev_tools_heading
        tool_bookmarks = []
        for block in page_blocks_sorted:
            block_order = block.get("order", 0)
            if block_order > dev_tools_order and block.get("type") == "bookmark":
                tool_bookmarks.append(block)
                if len(tool_bookmarks) >= 2:
                    break  # Only need 2
    
        if len(tool_bookmarks) < 2:
            errors.append(f"[X] Expected at least 2 bookmark blocks under Development Tools, found {len(tool_bookmarks)}")
        else:
            checks_passed.append(f"[C] Found at least 2 bookmark blocks under Development Tools ({len(tool_bookmarks)})")
    
        # Verify each required tool bookmark exists
        for required in required_tool_bookmarks:
            found = False
            for bookmark in tool_bookmarks:
                props = bookmark.get("properties", {})
                bookmark_url = props.get("url", "")
                bookmark_caption = props.get("caption", "")
            
                # Check URL
                url_match = (
                    bookmark_url == required["url"] or
                    bookmark_url.rstrip("/") == required["url"].rstrip("/")
                )
            
                # Check caption
                caption_lower = bookmark_caption.lower()
                caption_key_parts = required["caption"].split(" - ")[0].lower()
                caption_match = caption_key_parts in caption_lower
            
                if url_match and caption_match:
                    found = True
                    break
        
            if not found:
                errors.append(f"[X] Missing bookmark with URL '{required['url']}' and caption containing '{required['caption'].split(' - ')[0]}'")
            else:
                checks_passed.append(f"[C] has bookmark with URL '{required['url']}' and caption containing '{required['caption'].split(' - ')[0]}'")
    
        # 8. Verify blue callout with 💡 icon exists after Development Tools section
        last_tool_bookmark_order = max(b.get("order", 0) for b in tool_bookmarks) if tool_bookmarks else dev_tools_order
    
        callout_block = None
        for block in page_blocks_sorted:
            block_order = block.get("order", 0)
            if block.get("type") == "callout" and block_order > last_tool_bookmark_order:
                props = block.get("properties", {})
                bg_color = props.get("backgroundColor", "").lower()
                icon = props.get("icon", "")
            
                if "blue" in bg_color and icon == "💡":
                    callout_block = block
                    break
    
        if not callout_block:
            errors.append("[X] Missing blue callout with 💡 icon after Development Tools section")
        else:
            checks_passed.append("[C] has blue callout with 💡 icon after Development Tools section")
    
        # Verify callout content
        callout_content = callout_block.get("content", "").lower()
    
        if "last updated" not in callout_content:
            errors.append(f"[X] Callout missing 'Last updated' text. Got: '{callout_block.get('content', '')}'")
        else:
            checks_passed.append(f"[C] Callout has 'Last updated' text. Got: '{callout_block.get('content', '')}'")
    
        if "#dev-resources" not in callout_content:
            errors.append(f"[X] Callout missing '#dev-resources' channel reference. Got: '{callout_block.get('content', '')}'")
        else:
            checks_passed.append(f"[C] Callout has '#dev-resources' channel reference. Got: '{callout_block.get('content', '')}'")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

    # -----------------------------------------------------------------------------
    # Task: getting-started-todo-timeline-summary
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_getting_started_todo_timeline_summary(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Getting Started Todo Timeline Summary task.
    
    Goal: Navigate to 'Getting Started' page, find to-do blocks, insert heading_3
    '⏱️ Task Timeline' after last to-do, create status paragraphs for each to-do,
    add divider, callout based on completion percentage, and quote block.
    
    Validation steps:
    1. Find the 'Getting Started' page (page-1)
    2. Get all blocks and find the to-do blocks
    3. Verify heading_3 '⏱️ Task Timeline' exists after last to-do
    4. Verify status paragraphs exist for each to-do (✅ for checked, ⏳ for unchecked)
    5. Verify divider after status paragraphs
    6. Verify callout with appropriate color based on completion percentage
    7. Verify quote block with specific text
    
    Weights: All-or-nothing (1.0 if all pass, 0.0 otherwise)
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    
    # 1. Find the Getting Started page
    try:
        getting_started_page = _find_page_by_title(final_state_backend, "Getting Started")
        if not getting_started_page:
            errors.append("[X] Getting Started page not found")
        else:
            checks_passed.append("[C] Getting Started page found")
    
        page_id = getting_started_page.get("_id")
        page_blocks = _get_blocks_for_page(final_state_backend, page_id)
    
        if not page_blocks:
            errors.append("[X] No blocks found on Getting Started page")
        else:
            checks_passed.append("[C] blocks found on Getting Started page")
    
        # 2. Sort blocks by order and find to-do blocks
        page_blocks_sorted = sorted(page_blocks, key=lambda b: b.get("order", 0))
    
        todo_blocks = []
        last_todo_order = -1
        for block in page_blocks_sorted:
            if block.get("type") == "todo":
                todo_blocks.append(block)
                last_todo_order = max(last_todo_order, block.get("order", 0))
    
        if not todo_blocks:
            errors.append("[X] No to-do blocks found on Getting Started page")
        else:
            checks_passed.append("[C] to-do blocks found on Getting Started page")
    
        # Calculate completion percentage
        checked_count = sum(1 for t in todo_blocks if t.get("properties", {}).get("checked", False))
        total_todos = len(todo_blocks)
        completion_pct = (checked_count / total_todos) * 100 if total_todos > 0 else 0
    
        # 3. Verify heading_3 '⏱️ Task Timeline' exists after last to-do
        timeline_heading = None
        timeline_order = None
        for block in page_blocks_sorted:
            block_type = block.get("type", "")
            content = block.get("content", "")
            block_order = block.get("order", 0)
        
            if block_type in ["heading3", "heading_3"] and block_order > last_todo_order:
                if "⏱️" in content and "task timeline" in content.lower():
                    timeline_heading = block
                    timeline_order = block_order
                    break
    
        if timeline_heading is None:
            errors.append(f"[X] heading_3 '⏱️ Task Timeline' not found after last to-do (order > {last_todo_order})")
        else:
            checks_passed.append(f"[C] heading_3 '⏱️ Task Timeline' found after last to-do (order > {last_todo_order})")
    
        # 4. Verify status paragraphs for each to-do
        status_paragraphs = []
        for block in page_blocks_sorted:
            block_type = block.get("type", "")
            content = block.get("content", "")
            block_order = block.get("order", 0)
        
            if block_type == "paragraph" and block_order > timeline_order:
                # Check if it's a status paragraph (starts with ✅ or ⏳)
                if content.startswith("✅") or content.startswith("⏳"):
                    status_paragraphs.append(block)
    
        # Should have one status paragraph per todo
        if len(status_paragraphs) < total_todos:
            errors.append(f"[X] Expected at least {total_todos} status paragraphs, found {len(status_paragraphs)}")
        else:
            checks_passed.append(f"[C] Expected at least {total_todos} status paragraphs, found {len(status_paragraphs)}")
    
        # Verify status paragraphs have correct format
        for para in status_paragraphs:
            content = para.get("content", "")
            if content.startswith("✅"):
                if "completed" not in content.lower():
                    errors.append(f"[X] Checked item status paragraph should contain 'Completed'. Got: '{content}'")
            elif content.startswith("⏳"):
                if "pending" not in content.lower():
                    errors.append(f"[X] Unchecked item status paragraph should contain 'Pending'. Got: '{content}'")
                else:
                    checks_passed.append(f"[C] Unchecked item status paragraph should contain 'Pending'. Got: '{content}'")
    
        # 5. Verify divider after status paragraphs
        last_status_order = max(p.get("order", 0) for p in status_paragraphs) if status_paragraphs else timeline_order
    
        divider_found = False
        divider_order = None
        for block in page_blocks_sorted:
            if block.get("type") == "divider" and block.get("order", 0) > last_status_order:
                divider_found = True
                divider_order = block.get("order", 0)
                break
    
        if not divider_found:
            errors.append("[X] Divider not found after status paragraphs")
        else:
            checks_passed.append("[C] Divider found after status paragraphs")
    
        # 6. Verify callout with appropriate color based on completion percentage
        callout_found = False
        for block in page_blocks_sorted:
            if block.get("type") == "callout" and block.get("order", 0) > divider_order:
                props = block.get("properties", {})
                bg_color = props.get("backgroundColor", "").lower()
                icon = props.get("icon", "")
                content = block.get("content", "").lower()
            
                # Check if correct color based on completion percentage
                if completion_pct > 50:
                    # Should be green with 🎉 icon
                    if "green" in bg_color and "🎉" in icon:
                        if "great progress" in content or "completed" in content:
                            callout_found = True
                            break
                else:
                    # Should be red with ⚠️ icon
                    if "red" in bg_color and "⚠️" in icon:
                        if "needs attention" in content or "completed" in content:
                            callout_found = True
                            break
    
        if not callout_found:
            expected_color = "green" if completion_pct > 50 else "red"
            expected_icon = "🎉" if completion_pct > 50 else "⚠️"
            errors.append(f"[X] Callout with {expected_color}_background and {expected_icon} icon not found after divider (completion: {completion_pct:.0f}%)")
        else:
            checks_passed.append(f"[C] Callout with {expected_color}_background and {expected_icon} icon found after divider (completion: {completion_pct:.0f}%)")
    
        # 7. Verify quote block with specific text
        expected_quote = "the journey of a thousand miles begins with a single step"
        quote_found = False
        for block in page_blocks_sorted:
            if block.get("type") == "quote" and block.get("order", 0) > divider_order:
                content = block.get("content", "").lower()
                if expected_quote in content:
                    quote_found = True
                    break
    
        if not quote_found:
            errors.append(f"[X] Quote block with text '{expected_quote}' not found")
        else:
            checks_passed.append(f"[C] Quote block with text '{expected_quote}' found")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

    # -----------------------------------------------------------------------------
    # Task: architecture-overview-dashboard
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_architecture_overview_dashboard(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Architecture Overview Dashboard task.
    
    Goal: Create 'Architecture Overview Dashboard' as child of 'Architecture' page
    with hierarchy tree, documentation coverage, to-do blocks for each page,
    and warning callout if any pages have <5 blocks.
    
    Validation steps:
    1. Find 'Architecture' page under 'Project Documentation'
    2. Find 'Architecture Overview Dashboard' as child of 'Architecture'
    3. Verify heading1 '🏗️ Architecture Overview Dashboard'
    4. Verify heading2 '🌳 Architecture Tree'
    5. Verify bulleted list items with hierarchy (└─ prefix)
    6. Verify heading2 '📈 Documentation Coverage'
    7. Verify paragraph with total page count
    8. Verify to-do blocks for architecture pages (checked if >5 blocks)
    9. Verify yellow warning callout if any pages have <5 blocks
    
    Weights: All-or-nothing (1.0 if all pass, 0.0 otherwise)
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    
    # 1. Find 'Architecture' page
    try:
        architecture_page = _find_page_by_title(final_state_backend, "Architecture")
        if not architecture_page:
            errors.append("[X] Architecture page not found")
        else:
            checks_passed.append("[C] Architecture page found")

        architecture_id = architecture_page.get("_id")

        # 2. Find 'Architecture Overview Dashboard' as child of Architecture
        dashboard_page = _find_page_by_title_pattern_and_parent(final_state_backend, "Architecture Overview Dashboard", architecture_id)
        if not dashboard_page:
            errors.append("[X] Architecture Overview Dashboard page not found as child of Architecture")
        else:
            checks_passed.append("[C] Architecture Overview Dashboard page found as child of Architecture")

        dashboard_id = dashboard_page.get("_id")
        dashboard_blocks = _get_blocks_for_page(final_state_backend, dashboard_id)
    
        if not dashboard_blocks:
            errors.append("[X] No blocks found on Architecture Overview Dashboard page")
        else:
            checks_passed.append("[C] blocks found on Architecture Overview Dashboard page")
    
        # Sort blocks by order
        blocks_sorted = sorted(dashboard_blocks, key=lambda b: b.get("order", 0))
    
        # 3. Verify heading1 '🏗️ Architecture Overview Dashboard'
        heading1_found = False
        for block in blocks_sorted:
            if block.get("type") in ["heading1", "heading_1"]:
                content = block.get("content", "")
                if "🏗️" in content and "architecture overview dashboard" in content.lower():
                    heading1_found = True
                    break
    
        if not heading1_found:
            errors.append("[X] heading1 '🏗️ Architecture Overview Dashboard' not found")
        else:
            checks_passed.append("[C] heading1 '🏗️ Architecture Overview Dashboard' found")
    
        # 4. Verify heading2 '🌳 Architecture Tree'
        tree_heading = None
        tree_order = None
        for block in blocks_sorted:
            if block.get("type") in ["heading2", "heading_2"]:
                content = block.get("content", "")
                if "🌳" in content and "architecture tree" in content.lower():
                    tree_heading = block
                    tree_order = block.get("order", 0)
                    break
    
        if tree_heading is None:
            errors.append("[X] heading2 '🌳 Architecture Tree' not found")
        else:
            checks_passed.append("[C] heading2 '🌳 Architecture Tree' found")
    
        # 5. Verify bulleted list items with hierarchy
        bullet_items = []
        for block in blocks_sorted:
            block_order = block.get("order", 0)
            if block.get("type") in ["bulletedList", "bulleted_list"] and block_order > tree_order:
                content = block.get("content", "")
                bullet_items.append(content)
    
        if len(bullet_items) < 1:
            errors.append("[X] No bulleted list items found for architecture tree")
        else:
            checks_passed.append("[C] bulleted list items found for architecture tree")
    
        # Verify at least some items have hierarchy prefix
        has_hierarchy = any("└─" in item or "└" in item for item in bullet_items)
        if not has_hierarchy:
            errors.append("[X] Bulleted list items should use hierarchy prefix (└─)")
        else:
            checks_passed.append("[C] Bulleted list items should use hierarchy prefix (└─)")
    
        # 6. Verify heading2 '📈 Documentation Coverage'
        coverage_heading = None
        coverage_order = None
        for block in blocks_sorted:
            if block.get("type") in ["heading2", "heading_2"]:
                content = block.get("content", "")
                if "📈" in content and "documentation coverage" in content.lower():
                    coverage_heading = block
                    coverage_order = block.get("order", 0)
                    break
    
        if coverage_heading is None:
            errors.append("[X] heading2 '📈 Documentation Coverage' not found")
        else:
            checks_passed.append("[C] heading2 '📈 Documentation Coverage' found")
    
        # 7. Verify paragraph with total page count
        total_paragraph_found = False
        for block in blocks_sorted:
            if block.get("type") == "paragraph":
                content = block.get("content", "").lower()
                block_order = block.get("order", 0)
                if block_order > coverage_order and "total architecture pages" in content:
                    total_paragraph_found = True
                    break
    
        if not total_paragraph_found:
            errors.append("[X] Paragraph with 'Total architecture pages: [X]' not found")
        else:
            checks_passed.append("[C] Paragraph with 'Total architecture pages: [X]' found")
    
        # 8. Verify to-do blocks exist for architecture pages
        todo_blocks = [b for b in blocks_sorted if b.get("type") == "todo"]
    
        if len(todo_blocks) < 1:
            errors.append("[X] No to-do blocks found for architecture page documentation status")
        else:
            checks_passed.append("[C] to-do blocks found for architecture page documentation status")
    
        # 9. Check for warning callout if any pages have <5 blocks
        # Get all architecture sub-pages and their block counts
        def get_architecture_pages(parent_id: str) -> List[Dict[str, Any]]:
            result = []
            child_pages = _get_child_pages(final_state_backend, parent_id)
            for page in child_pages:
                page_blocks = _get_blocks_for_page(final_state_backend, page.get("_id"))
                result.append({
                    "page": page,
                    "block_count": len(page_blocks)
                })
                result.extend(get_architecture_pages(page.get("_id")))
            return result

        arch_pages = get_architecture_pages(architecture_id)
        has_sparse_pages = any(p["block_count"] < 5 for p in arch_pages)
    
        # Look for yellow warning callout
        warning_callout_found = False
        for block in blocks_sorted:
            if block.get("type") == "callout":
                props = block.get("properties", {})
                bg_color = props.get("backgroundColor", "").lower()
                icon = props.get("icon", "")
                content = block.get("content", "").lower()
            
                if "yellow" in bg_color and "⚠️" in icon:
                    if "warning" in content or "need" in content or "documentation" in content:
                        warning_callout_found = True
                        break
    
        if has_sparse_pages and not warning_callout_found:
            errors.append("[X] Warning callout with yellow_background and ⚠️ icon not found (some pages have <5 blocks)")
        else:
            checks_passed.append("[C] Warning callout with yellow_background and ⚠️ icon found (some pages have <5 blocks)")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

    # -----------------------------------------------------------------------------
    # Task: getting-started-key-features-content-insertion
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_getting_started_key_features_content_insertion(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Getting Started Key Features Content Insertion task.
    
    Goal: Navigate to 'Getting Started' page and insert new content blocks
    between the 'Key Features' heading_2 and the first bulletedList block.
    
    Validation steps:
    1. Find the 'Getting Started' page (page-1)
    2. Find heading2 'Key Features'
    3. Find first bulletedList after Key Features ('Rich text editing...')
    4. Verify callout with yellow_background, ⚡ icon exists AFTER heading but BEFORE bullets
    5. Verify divider exists AFTER callout but BEFORE bullets
    6. Verify paragraph with specific text exists AFTER divider but BEFORE bullets
    
    Weights: All-or-nothing (1.0 if all pass, 0.0 otherwise)
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    
    # 1. Find the Getting Started page
    try:
        getting_started_page = _find_page_by_title(final_state_backend, "Getting Started")
        if not getting_started_page:
            errors.append("[X] Getting Started page not found")
        else:
            checks_passed.append("[C] Getting Started page found")
    
        page_id = getting_started_page.get("_id")
        page_blocks = _get_blocks_for_page(final_state_backend, page_id)
    
        if not page_blocks:
            errors.append("[X] No blocks found on Getting Started page")
        else:
            checks_passed.append("[C] blocks found on Getting Started page")
    
        # Sort blocks by order
        page_blocks_sorted = sorted(page_blocks, key=lambda b: b.get("order", 0))
    
        # 2. Find heading2 'Key Features'
        key_features_heading = None
        key_features_order = None
        for block in page_blocks_sorted:
            if block.get("type") in ["heading2", "heading_2"]:
                content = block.get("content", "").lower()
                if "key features" in content:
                    key_features_heading = block
                    key_features_order = block.get("order", 0)
                    break
    
        if key_features_heading is None:
            errors.append("[X] heading2 'Key Features' not found")
        else:
            checks_passed.append("[C] heading2 'Key Features' found")
    
        # 3. Find first bulletedList after Key Features (should be 'Rich text editing...')
        first_bullet = None
        first_bullet_order = None
        for block in page_blocks_sorted:
            block_order = block.get("order", 0)
            if block.get("type") in ["bulletedList", "bulleted_list"] and block_order > key_features_order:
                first_bullet = block
                first_bullet_order = block_order
                break
    
        if first_bullet is None:
            errors.append("[X] No bulletedList found after 'Key Features' heading")
        else:
            checks_passed.append("[C] bulletedList found after 'Key Features' heading")
    
        # Verify it's the expected first bullet
        first_bullet_content = first_bullet.get("content", "").lower()
        if "rich text editing" not in first_bullet_content:
            # It's okay if content was inserted, but there should be a bullet about rich text somewhere
            pass
    
        # 4. Verify callout with yellow_background, ⚡ icon exists AFTER heading but BEFORE bullets
        expected_callout_text = "note: these features require specific user permissions to access"
        callout_found = False
        callout_order = None
    
        for block in page_blocks_sorted:
            block_order = block.get("order", 0)
            if block.get("type") == "callout" and block_order > key_features_order and block_order < first_bullet_order:
                props = block.get("properties", {})
                bg_color = props.get("backgroundColor", "").lower()
                icon = props.get("icon", "")
                content = block.get("content", "").lower()
            
                if "yellow" in bg_color and "⚡" in icon:
                    if expected_callout_text in content:
                        callout_found = True
                        callout_order = block_order
                        break
                    else:
                        errors.append(f"[X] Callout found but text doesn't match. Expected: '{expected_callout_text}'. Got: '{block.get('content', '')}'")
    
        if not callout_found:
            errors.append("[X] Callout with yellow_background, ⚡ icon not found between Key Features heading and first bullet")
        else:
            checks_passed.append("[C] Callout with yellow_background, ⚡ icon found between Key Features heading and first bullet")
    
        # 5. Verify divider exists AFTER callout but BEFORE bullets
        divider_found = False
        divider_order = None
        for block in page_blocks_sorted:
            block_order = block.get("order", 0)
            if block.get("type") == "divider" and block_order > callout_order and block_order < first_bullet_order:
                divider_found = True
                divider_order = block_order
                break
    
        if not divider_found:
            errors.append("[X] Divider not found between callout and first bullet")
        else:
            checks_passed.append("[C] Divider found between callout and first bullet")
    
        # 6. Verify paragraph with specific text exists AFTER divider but BEFORE bullets
        expected_paragraph_text = "for detailed feature access levels, consult the engineering wiki documentation"
        paragraph_found = False
    
        for block in page_blocks_sorted:
            block_order = block.get("order", 0)
            if block.get("type") == "paragraph" and block_order > divider_order and block_order < first_bullet_order:
                content = block.get("content", "").lower()
                if expected_paragraph_text in content:
                    paragraph_found = True
                    break
    
        if not paragraph_found:
            errors.append(f"[X] Paragraph with text '{expected_paragraph_text}' not found between divider and first bullet")
        else:
            checks_passed.append(f"[C] Paragraph with text '{expected_paragraph_text}' found between divider and first bullet")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

    # -----------------------------------------------------------------------------
    # Task: component-inventory-report
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_component_inventory_report(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validates the Component Inventory Report task.
    
    Goal: Create a 'Component Inventory Report' as a child of 'Design System' page
    with proper structure including component categories, coverage analysis, and recommendations.
    
    Validation steps:
    1. Find 'Design System' page (page-35 in workspace-2)
    2. Check that 'Component Inventory Report' page exists as its child
    3. Verify heading_1 '🧩 Component Inventory Report'
    4. Verify heading_2 with 'Report Generated:' and a date
    5. Verify heading_2 '🎨 Component Categories'
    6. For each component type: heading_3, callout with correct background color, bulleted list
    7. Verify heading_2 '📊 Coverage Analysis' with paragraphs for totals
    8. Verify heading_2 '🎯 Recommendations' with exactly 3 numbered items
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    # Get all pages and blocks
    
    # Step 1: Find Design System page (page-35 in workspace-2)
    try:
        design_system_page = _find_page_by_title(final_state_backend, "Design System")
        if not design_system_page:
            errors.append("[X] Design System page not found")
        else:
            checks_passed.append("[C] Design System page found")

        design_system_id = design_system_page.get("_id")

        # Step 2: Find Component Inventory Report as child of Design System
        report_page = _find_page_by_title_pattern_and_parent(final_state_backend, "Component Inventory Report", design_system_id)
        if not report_page:
            errors.append("[X] Component Inventory Report page not found as child of Design System")
        else:
            checks_passed.append("[C] Component Inventory Report page found as child of Design System")

        report_page_id = report_page.get("_id")

        # Get all blocks for the report page, sorted by order
        report_blocks = _get_blocks_for_page(final_state_backend, report_page_id)
        report_blocks_sorted = sorted(report_blocks, key=lambda b: b.get("order", 0))
    
        if not report_blocks:
            errors.append("[X] Component Inventory Report page has no content blocks")
        else:
            checks_passed.append("[C] Component Inventory Report page has content blocks")
    
        # Step 3: Verify heading_1 '🧩 Component Inventory Report'
        heading1_found = False
        for block in report_blocks_sorted:
            if block.get("type") == "heading1":
                content = block.get("content", "")
                if "component inventory report" in content.lower():
                    heading1_found = True
                    break
    
        if not heading1_found:
            errors.append("[X] heading_1 '🧩 Component Inventory Report' not found")
        else:
            checks_passed.append("[C] heading_1 '🧩 Component Inventory Report' found")
    
        # Step 4: Verify heading_2 with 'Report Generated:' and a date
        report_date_found = False
        for block in report_blocks_sorted:
            if block.get("type") == "heading2":
                content = block.get("content", "").lower()
                if "report generated" in content:
                    report_date_found = True
                    break
    
        if not report_date_found:
            errors.append("[X] heading_2 with 'Report Generated:' not found")
        else:
            checks_passed.append("[C] heading_2 with 'Report Generated:' found")
    
        # Step 5: Verify heading_2 '🎨 Component Categories'
        categories_heading_found = False
        categories_heading_order = None
        for block in report_blocks_sorted:
            if block.get("type") == "heading2":
                content = block.get("content", "").lower()
                if "component categories" in content:
                    categories_heading_found = True
                    categories_heading_order = block.get("order", 0)
                    break
    
        if not categories_heading_found:
            errors.append("[X] heading_2 '🎨 Component Categories' not found")
        else:
            checks_passed.append("[C] heading_2 '🎨 Component Categories' found")
    
        # Step 6: Verify heading_2 '📊 Coverage Analysis' with required paragraphs
        coverage_heading_found = False
        coverage_heading_order = None
        for block in report_blocks_sorted:
            if block.get("type") == "heading2":
                content = block.get("content", "").lower()
                if "coverage analysis" in content:
                    coverage_heading_found = True
                    coverage_heading_order = block.get("order", 0)
                    break
    
        if not coverage_heading_found:
            errors.append("[X] heading_2 '📊 Coverage Analysis' not found")
        else:
            checks_passed.append("[C] heading_2 '📊 Coverage Analysis' found")
    
        # Check for coverage analysis paragraphs
        coverage_paragraphs = []
        for block in report_blocks_sorted:
            block_order = block.get("order", 0)
            if block.get("type") == "paragraph" and coverage_heading_order is not None:
                if block_order > coverage_heading_order:
                    coverage_paragraphs.append(block.get("content", "").lower())
    
        # Check for required coverage text patterns
        has_total_types = any("total component types" in p for p in coverage_paragraphs)
        has_total_components = any("total individual components" in p for p in coverage_paragraphs)
        has_average = any("average" in p and "per type" in p for p in coverage_paragraphs)
    
        if not has_total_types:
            errors.append("[X] Coverage Analysis missing 'Total component types' paragraph")
        else:
            checks_passed.append("[C] Coverage Analysis has 'Total component types' paragraph")
        if not has_total_components:
            errors.append("[X] Coverage Analysis missing 'Total individual components' paragraph")
        else:
            checks_passed.append("[C] Coverage Analysis has 'Total individual components' paragraph")
        if not has_average:
            errors.append("[X] Coverage Analysis missing 'Average components per type' paragraph")
        else:
            checks_passed.append("[C] Coverage Analysis has 'Average components per type' paragraph")
    
        # Step 7: Verify heading_2 '🎯 Recommendations' with exactly 3 numbered items
        recommendations_heading_found = False
        recommendations_heading_order = None
        for block in report_blocks_sorted:
            if block.get("type") == "heading2":
                content = block.get("content", "").lower()
                if "recommendations" in content:
                    recommendations_heading_found = True
                    recommendations_heading_order = block.get("order", 0)
                    break
    
        if not recommendations_heading_found:
            errors.append("[X] heading_2 '🎯 Recommendations' not found")
        else:
            checks_passed.append("[C] heading_2 '🎯 Recommendations' found")
    
        # Count numbered list items after recommendations heading
        numbered_items = []
        for block in report_blocks_sorted:
            block_order = block.get("order", 0)
            if block.get("type") == "numberedList" and recommendations_heading_order is not None:
                if block_order > recommendations_heading_order:
                    numbered_items.append(block)
    
        if len(numbered_items) != 3:
            errors.append(f"[X] Recommendations section should have exactly 3 numbered items, found {len(numbered_items)}")
        else:
            checks_passed.append(f"[C] Recommendations section should have exactly 3 numbered items, found {len(numbered_items)}")
    
        # Verify the numbered items contain expected recommendation text
        expected_recommendations = [
            "expand categories",
            "consolidating",
            "document usage"
        ]
    
        found_recommendations = 0
        for item in numbered_items:
            content = item.get("content", "").lower()
            for expected in expected_recommendations:
                if expected in content:
                    found_recommendations += 1
                    break
    
        if found_recommendations < 3:
            errors.append(f"[X] Recommendations section missing expected recommendation content. Found {found_recommendations}/3 expected recommendations")
        else:
            checks_passed.append(f"[C] Recommendations section has expected recommendation content. Found {found_recommendations}/3 expected recommendations")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

    # -----------------------------------------------------------------------------
    # Task: company-handbook-culture-section-v2
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_company_handbook_culture_section(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Company Handbook culture section reorganization task.
    
    Goal: Navigate to the 'Company Handbook' page and perform a complex section 
    reorganization. Swap 'Our Values' and 'Benefits' sections, add a new 
    '🌟 Culture & Team Building' section after 'Work Policies', and add a 
    callout at the end of the 'Time Off' subsection.
    
    Validation steps (ordered):
    1. Find the 'Company Handbook' page
    2. Get all blocks and sort by order
    3. Verify 'Benefits' section now appears BEFORE 'Our Values' (swapped positions)
    4. Verify 'Work Policies' section still exists
    5. Verify new '🌟 Culture & Team Building' heading_2 exists AFTER 'Work Policies' but BEFORE the swapped 'Our Values'
    6. Verify heading_3 '🎯 Monthly Team Events' exists under Culture section
    7. Verify paragraph with exact text 'We host monthly team-building activities to strengthen our bonds and have fun together.'
    8. Verify exactly 3 bulleted list items with correct text under Culture section
    9. Verify callout with blue_background, icon '💙', and correct text exists at end of Time Off subsection
    10. Verify original content of 'Our Values' and 'Benefits' sections is preserved
    
    Weights: All-or-nothing (1.0 if all pass, 0.0 otherwise)
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    
    # Step 1: Find the Company Handbook page
    try:
        handbook_page = _find_page_by_title(final_state_backend, "Company Handbook")
        if not handbook_page:
            errors.append("[X] Company Handbook page not found")
        else:
            checks_passed.append("[C] Company Handbook page found")
    
        page_id = handbook_page.get("_id")
        page_blocks = _get_blocks_for_page(final_state_backend, page_id)
    
        if not page_blocks:
            errors.append("[X] No blocks found on Company Handbook page")
        else:
            checks_passed.append("[C] blocks found on Company Handbook page")
    
        # Step 2: Sort blocks by order
        page_blocks_sorted = sorted(page_blocks, key=lambda b: b.get("order", 0))
    
        # Step 3-5: Find positions of key sections
        our_values_idx = None
        benefits_idx = None
        work_policies_idx = None
        culture_section_idx = None
        time_off_idx = None
    
        for idx, block in enumerate(page_blocks_sorted):
            block_type = block.get("type", "")
            content = block.get("content", "")
            content_lower = content.lower()
        
            if block_type == "heading2":
                if "our values" in content_lower:
                    our_values_idx = idx
                elif "benefits" in content_lower:
                    benefits_idx = idx
                elif "work policies" in content_lower:
                    work_policies_idx = idx
                elif "culture" in content_lower and "team building" in content_lower:
                    culture_section_idx = idx
            elif block_type == "heading3":
                if "time off" in content_lower:
                    time_off_idx = idx
    
        # Validation 3: Benefits must appear BEFORE Our Values (swapped)
        if benefits_idx is None:
            errors.append("[X] heading_2 'Benefits' not found")
        else:
            checks_passed.append("[C] heading_2 'Benefits' found")
    
        if our_values_idx is None:
            errors.append("[X] heading_2 'Our Values' not found")
        else:
            checks_passed.append("[C] heading_2 'Our Values' found")
    
        if benefits_idx >= our_values_idx:
            errors.append(f"[X] 'Benefits' (idx {benefits_idx}) must appear BEFORE 'Our Values' (idx {our_values_idx}) - sections should be swapped")
        else:
            checks_passed.append(f"[C] 'Benefits' (idx {benefits_idx}) must appear BEFORE 'Our Values' (idx {our_values_idx}) - sections should be swapped")
    
        # Validation 4: Work Policies must exist
        if work_policies_idx is None:
            errors.append("[X] heading_2 'Work Policies' not found")
        else:
            checks_passed.append("[C] heading_2 'Work Policies' found")
    
        # Validation 5: Culture & Team Building must exist AFTER Work Policies but BEFORE Our Values
        if culture_section_idx is None:
            errors.append("[X] heading_2 '🌟 Culture & Team Building' not found")
        else:
            checks_passed.append("[C] heading_2 '🌟 Culture & Team Building' found")
    
        if culture_section_idx <= work_policies_idx:
            errors.append(f"[X] 'Culture & Team Building' (idx {culture_section_idx}) must appear AFTER 'Work Policies' (idx {work_policies_idx})")
        else:
            checks_passed.append(f"[C] 'Culture & Team Building' (idx {culture_section_idx}) must appear AFTER 'Work Policies' (idx {work_policies_idx})")
    
        if culture_section_idx >= our_values_idx:
            errors.append(f"[X] 'Culture & Team Building' (idx {culture_section_idx}) must appear BEFORE 'Our Values' (idx {our_values_idx})")
        else:
            checks_passed.append(f"[C] 'Culture & Team Building' (idx {culture_section_idx}) must appear BEFORE 'Our Values' (idx {our_values_idx})")
    
        # Validation 6: Find heading_3 '🎯 Monthly Team Events' under Culture section
        monthly_events_idx = None
        for idx in range(culture_section_idx + 1, our_values_idx):
            block = page_blocks_sorted[idx]
            if block.get("type") == "heading3":
                content = block.get("content", "")
                if "monthly team events" in content.lower():
                    monthly_events_idx = idx
                    break
    
        if monthly_events_idx is None:
            errors.append("[X] heading_3 '🎯 Monthly Team Events' not found under Culture & Team Building section")
        else:
            checks_passed.append("[C] heading_3 '🎯 Monthly Team Events' found under Culture & Team Building section")
    
        # Validation 7: Find paragraph with exact text
        expected_paragraph = "we host monthly team-building activities to strengthen our bonds and have fun together."
        paragraph_found = False
    
        for idx in range(monthly_events_idx + 1, our_values_idx):
            block = page_blocks_sorted[idx]
            if block.get("type") == "paragraph":
                content = block.get("content", "").lower()
                if expected_paragraph in content:
                    paragraph_found = True
                    break
    
        if not paragraph_found:
            errors.append(f"[X] Paragraph with text 'We host monthly team-building activities to strengthen our bonds and have fun together.' not found under Monthly Team Events")
        else:
            checks_passed.append(f"[C] Paragraph with text 'We host monthly team-building activities to strengthen our bonds and have fun together.' found under Monthly Team Events")
    
        # Validation 8: Find exactly 3 bulleted list items with correct text
        expected_bullets = [
            "game nights every first friday",
            "team lunch every third wednesday",
            "creative workshops quarterly"
        ]
    
        found_bullets = []
        for idx in range(culture_section_idx + 1, our_values_idx):
            block = page_blocks_sorted[idx]
            if block.get("type") == "bulletedList":
                content = block.get("content", "").lower()
                found_bullets.append(content)
    
        # Check that all expected bullets are found
        for expected in expected_bullets:
            found = False
            for bullet in found_bullets:
                if expected in bullet:
                    found = True
                    break
            if not found:
                errors.append(f"[X] Bulleted list item containing '{expected}' not found in Culture section")
            else:
                checks_passed.append(f"[C] Bulleted list item containing '{expected}' found in Culture section")
    
        # Validation 9: Find callout at end of Time Off subsection
        # Time Off is a heading_3, so we need to find the callout between Time Off and the next heading (Benefits or Culture)
        if time_off_idx is None:
            errors.append("[X] heading_3 'Time Off' not found")
        else:
            checks_passed.append("[C] heading_3 'Time Off' found")
    
        # Find the next heading after Time Off (should be either Culture or another heading)
        time_off_section_end = culture_section_idx  # The section ends at Culture heading
    
        callout_found = False
        callout_valid = False
    
        for idx in range(time_off_idx + 1, time_off_section_end):
            block = page_blocks_sorted[idx]
            if block.get("type") == "callout":
                callout_found = True
                props = block.get("properties", {})
                bg_color = props.get("backgroundColor", "").lower()
                icon = props.get("icon", "")
                content = block.get("content", "").lower()
            
                expected_callout_text = "taking time off is essential for maintaining work-life balance and peak performance"
            
                # Check for blue background and 💙 icon
                if "blue" in bg_color and "💙" in icon:
                    if expected_callout_text in content:
                        callout_valid = True
                        break
    
        if not callout_found:
            errors.append("[X] Callout block not found at end of Time Off subsection")
        else:
            checks_passed.append("[C] Callout block found at end of Time Off subsection")
    
        if not callout_valid:
            errors.append("[X] Callout block should have blue_background, '💙' icon, and contain 'Remember: Taking time off is essential for maintaining work-life balance and peak performance.'")
        else:
            checks_passed.append("[C] Callout block should have blue_background, '💙' icon, and contain 'Remember: Taking time off is essential for maintaining work-life balance and peak performance.'")
    
        # Validation 10: Verify original content of Our Values and Benefits sections is preserved
        # Check Our Values section has its original values
        our_values_end_idx = len(page_blocks_sorted)
        for idx in range(our_values_idx + 1, len(page_blocks_sorted)):
            if page_blocks_sorted[idx].get("type") == "heading2":
                our_values_end_idx = idx
                break
    
        our_values_bullets = []
        for idx in range(our_values_idx + 1, our_values_end_idx):
            block = page_blocks_sorted[idx]
            if block.get("type") == "bulletedList":
                our_values_bullets.append(block.get("content", "").lower())
    
        original_values = ["customer first", "excellence", "collaboration"]
        for value in original_values:
            found = False
            for bullet in our_values_bullets:
                if value in bullet:
                    found = True
                    break
            if not found:
                errors.append(f"[X] Original value '{value}' not found in Our Values section - content may not be preserved")
            else:
                checks_passed.append(f"[C] Original value '{value}' found in Our Values section - content may be preserved")
    
        # Check Benefits section has its original items
        benefits_end_idx = work_policies_idx  # Benefits ends before Work Policies
    
        benefits_items = []
        for idx in range(benefits_idx + 1, benefits_end_idx):
            block = page_blocks_sorted[idx]
            block_type = block.get("type", "")
            if block_type in ["numberedList", "bulletedList"]:
                benefits_items.append(block.get("content", "").lower())
    
        original_benefits = [
            "comprehensive health insurance",
            "401(k) matching",
            "learning stipend",
            "home office"
        ]
    
        for benefit in original_benefits:
            found = False
            for item in benefits_items:
                if benefit in item:
                    found = True
                    break
            if not found:
                errors.append(f"[X] Original benefit containing '{benefit}' not found in Benefits section - content may not be preserved")
            else:
                checks_passed.append(f"[C] Original benefit containing '{benefit}' found in Benefits section - content may be preserved")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

    # -----------------------------------------------------------------------------
    # Task: engineering-team-hub
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_engineering_team_hub(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Engineering Team Hub page creation.
    
    Goal: Create 'Engineering Team Hub' page under 'Engineering Wiki' with:
    1. New page titled 'Engineering Team Hub' under 'Engineering Wiki'
    2. heading_1 '🛠️ Engineering Team Hub'
    3. heading_2 '🔗 Quick Links'
    4. Bookmark blocks for Code Standards, Project Documentation, Design System
    5. heading_2 '📊 Team Resources' with orange callout containing ⚡ icon
    6. heading_2 '🎯 Current Sprint' with paragraph and bookmark
    7. Divider
    8. heading_3 '🔄 Last Updated' with italic date
    
    Validation steps (all-or-nothing):
    1. Find 'Engineering Team Hub' page as child of 'Engineering Wiki'
    2. Verify heading_1 with 🛠️ exists
    3. Verify heading_2 '🔗 Quick Links' exists
    4. Verify bookmark blocks exist
    5. Verify heading_2 '📊 Team Resources' exists with orange callout
    6. Verify heading_2 '🎯 Current Sprint' exists
    7. Verify divider exists
    8. Verify heading_3 '🔄 Last Updated' exists
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    
    # 1. Find Engineering Wiki page
    try:
        engineering_wiki = _find_page_by_title(final_state_backend, "Engineering Wiki")
        if not engineering_wiki:
            errors.append("[X] Engineering Wiki page not found")
        else:
            checks_passed.append("[C] Engineering Wiki page found")

        wiki_id = engineering_wiki.get("_id")

        # 2. Find Engineering Team Hub as child of Engineering Wiki
        hub_page = _find_page_by_title_pattern_and_parent(final_state_backend, "Engineering Team Hub", wiki_id)
        if not hub_page:
            errors.append("[X] Engineering Team Hub page not found as child of Engineering Wiki")
        else:
            checks_passed.append("[C] Engineering Team Hub page found as child of Engineering Wiki")

        page_id = hub_page.get("_id")
        page_blocks = _get_blocks_for_page(final_state_backend, page_id)
    
        if not page_blocks:
            errors.append("[X] Engineering Team Hub page has no blocks")
        else:
            checks_passed.append("[C] Engineering Team Hub page has blocks")
    
        page_blocks_sorted = sorted(page_blocks, key=lambda b: b.get("order", 0))
    
        # 3. Verify heading_1 with 🛠️
        heading1_found = False
        for block in page_blocks_sorted:
            if block.get("type") == "heading1":
                content = block.get("content", "")
                if "🛠️" in content and "engineering team hub" in content.lower():
                    heading1_found = True
                    break
    
        if not heading1_found:
            errors.append("[X] Missing heading_1 with '🛠️ Engineering Team Hub'")
        else:
            checks_passed.append("[C] has heading_1 with '🛠️ Engineering Team Hub'")
    
        # 4. Verify heading_2 '🔗 Quick Links'
        quick_links_found = False
        for block in page_blocks_sorted:
            if block.get("type") == "heading2":
                content = block.get("content", "")
                if "🔗" in content and "quick links" in content.lower():
                    quick_links_found = True
                    break
    
        if not quick_links_found:
            errors.append("[X] Missing heading_2 '🔗 Quick Links'")
        else:
            checks_passed.append("[C] has heading_2 '🔗 Quick Links'")
    
        # 5. Verify bookmark blocks exist (at least 3)
        bookmark_count = sum(1 for b in page_blocks_sorted if b.get("type") == "bookmark")
        if bookmark_count < 3:
            errors.append(f"[X] Expected at least 3 bookmark blocks, found {bookmark_count}")
        else:
            checks_passed.append(f"[C] Found at least 3 bookmark blocks ({bookmark_count})")
    
        # 6. Verify heading_2 '📊 Team Resources' with orange callout
        team_resources_found = False
        team_resources_order = -1
        for block in page_blocks_sorted:
            if block.get("type") == "heading2":
                content = block.get("content", "")
                if "📊" in content and "team resources" in content.lower():
                    team_resources_found = True
                    team_resources_order = block.get("order", 0)
                    break
    
        if not team_resources_found:
            errors.append("[X] Missing heading_2 '📊 Team Resources'")
        else:
            checks_passed.append("[C] has heading_2 '📊 Team Resources'")
    
        # Check for orange callout with ⚡ icon after Team Resources
        orange_callout_found = False
        for block in page_blocks_sorted:
            if block.get("type") == "callout" and block.get("order", 0) > team_resources_order:
                props = block.get("properties", {})
                bg_color = props.get("backgroundColor", "").lower()
                icon = props.get("icon", "")
                if "orange" in bg_color and icon == "⚡":
                    orange_callout_found = True
                    break
    
        if not orange_callout_found:
            errors.append("[X] Missing orange callout with ⚡ icon after Team Resources section")
        else:
            checks_passed.append("[C] has orange callout with ⚡ icon after Team Resources section")
    
        # 7. Verify heading_2 '🎯 Current Sprint'
        current_sprint_found = False
        for block in page_blocks_sorted:
            if block.get("type") == "heading2":
                content = block.get("content", "")
                if "🎯" in content and "current sprint" in content.lower():
                    current_sprint_found = True
                    break
    
        if not current_sprint_found:
            errors.append("[X] Missing heading_2 '🎯 Current Sprint'")
        else:
            checks_passed.append("[C] has heading_2 '🎯 Current Sprint'")
    
        # 8. Verify divider exists
        divider_found = any(b.get("type") == "divider" for b in page_blocks_sorted)
        if not divider_found:
            errors.append("[X] Missing divider block")
        else:
            checks_passed.append("[C] has divider block")
    
        # 9. Verify heading_3 '🔄 Last Updated'
        last_updated_found = False
        for block in page_blocks_sorted:
            if block.get("type") == "heading3":
                content = block.get("content", "")
                if "🔄" in content and "last updated" in content.lower():
                    last_updated_found = True
                    break
    
        if not last_updated_found:
            errors.append("[X] Missing heading_3 '🔄 Last Updated'")
        else:
            checks_passed.append("[C] has heading_3 '🔄 Last Updated'")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

    # -----------------------------------------------------------------------------
    # Task: engineering-team-summary-v2
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_engineering_team_summary(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Engineering Team Summary page creation.
    
    Goal: Create 'Engineering Team Summary' page under 'Team Directory' analyzing
    pages with 'Engineering' or 'Tech' in titles with block statistics.
    
    Validation steps (all-or-nothing):
    1. Find 'Engineering Team Summary' page as child of 'Team Directory'
    2. Verify heading_1 '🔧 Engineering Documentation Overview' exists
    3. Verify heading_2 '📊 Content Statistics' exists
    4. Verify blue callout with date exists
    5. Verify heading_3 entries exist for analyzed pages (with 📄)
    6. Verify bulleted list items with statistics
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    
    # 1. Find Team Directory page
    try:
        team_directory = _find_page_by_title(final_state_backend, "Team Directory")
        if not team_directory:
            errors.append("[X] Team Directory page not found")
        else:
            checks_passed.append("[C] Team Directory page found")
    
        team_dir_id = team_directory.get("_id")
    
        # 2. Find Engineering Team Summary as child of Team Directory
        summary_page = _find_page_by_title_pattern_and_parent(final_state_backend, "Engineering Team Summary", team_dir_id)
        if not summary_page:
            errors.append("[X] Engineering Team Summary page not found as child of Team Directory")
        else:
            checks_passed.append("[C] Engineering Team Summary page found as child of Team Directory")

        page_id = summary_page.get("_id")
        page_blocks = _get_blocks_for_page(final_state_backend, page_id)
    
        if not page_blocks:
            errors.append("[X] Engineering Team Summary page has no blocks")
        else:
            checks_passed.append("[C] Engineering Team Summary page has blocks")
    
        page_blocks_sorted = sorted(page_blocks, key=lambda b: b.get("order", 0))
    
        # 3. Verify heading_1 '🔧 Engineering Documentation Overview'
        heading1_found = False
        for block in page_blocks_sorted:
            if block.get("type") == "heading1":
                content = block.get("content", "")
                if "🔧" in content and "engineering" in content.lower() and "overview" in content.lower():
                    heading1_found = True
                    break
    
        if not heading1_found:
            errors.append("[X] Missing heading_1 with '🔧 Engineering Documentation Overview'")
        else:
            checks_passed.append("[C] has heading_1 with '🔧 Engineering Documentation Overview'")
    
        # 4. Verify heading_2 '📊 Content Statistics'
        content_stats_found = False
        content_stats_order = -1
        for block in page_blocks_sorted:
            if block.get("type") == "heading2":
                content = block.get("content", "")
                if "📊" in content and "content statistics" in content.lower():
                    content_stats_found = True
                    content_stats_order = block.get("order", 0)
                    break
    
        if not content_stats_found:
            errors.append("[X] Missing heading_2 '📊 Content Statistics'")
        else:
            checks_passed.append("[C] has heading_2 '📊 Content Statistics'")
    
        # 5. Verify blue callout with date
        blue_callout_found = False
        for block in page_blocks_sorted:
            if block.get("type") == "callout" and block.get("order", 0) > content_stats_order:
                props = block.get("properties", {})
                bg_color = props.get("backgroundColor", "").lower()
                content = block.get("content", "").lower()
                if "blue" in bg_color and ("last updated" in content or "updated" in content):
                    blue_callout_found = True
                    break
    
        if not blue_callout_found:
            errors.append("[X] Missing blue callout with date under Content Statistics")
        else:
            checks_passed.append("[C] has blue callout with date under Content Statistics")
    
        # 6. Verify heading_3 entries exist (with 📄)
        heading3_with_page = False
        for block in page_blocks_sorted:
            if block.get("type") == "heading3":
                content = block.get("content", "")
                if "📄" in content:
                    heading3_with_page = True
                    break
    
        if not heading3_with_page:
            errors.append("[X] Missing heading_3 entries with '📄' for analyzed pages")
        else:
            checks_passed.append("[C] has heading_3 entries with '📄' for analyzed pages")
    
        # 7. Verify bulleted list items with statistics exist
        stats_bullets_found = False
        for block in page_blocks_sorted:
            if block.get("type") == "bulletedList":
                content = block.get("content", "").lower()
                if "section headers" in content or "task items" in content or "completion rate" in content:
                    stats_bullets_found = True
                    break
    
        if not stats_bullets_found:
            errors.append("[X] Missing bulleted list items with statistics")
        else:
            checks_passed.append("[C] has bulleted list items with statistics")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

    # -----------------------------------------------------------------------------
    # Task: engineering-wiki-reorganize-enhance-v2
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_engineering_wiki_reorganize_enhance(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Engineering Wiki reorganization and enhancement.
    
    Goal: On Engineering Wiki page:
    1. Swap 'Tech Stack' and 'Development Setup' sections
    2. Add code block with bash after Environment Variables heading_3
    3. Add heading_2 'Useful Commands' at the end with numbered list
    
    Validation steps (all-or-nothing):
    1. Find Engineering Wiki page
    2. Verify Tech Stack heading comes AFTER Development Setup (swapped)
    3. Verify code block with language 'bash' exists after Environment Variables
    4. Verify code block contains the required environment variables
    5. Verify heading_2 'Useful Commands' exists at end
    6. Verify numbered list with npm commands exists
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    
    # 1. Find Engineering Wiki page (page-4)
    try:
        wiki_page = _find_page_by_title(final_state_backend, "Engineering Wiki")
        if not wiki_page:
            errors.append("[X] Engineering Wiki page not found")
        else:
            checks_passed.append("[C] Engineering Wiki page found")
    
        page_id = wiki_page.get("_id")
        page_blocks = _get_blocks_for_page(final_state_backend, page_id)
    
        if not page_blocks:
            errors.append("[X] Engineering Wiki page has no blocks")
        else:
            checks_passed.append("[C] Engineering Wiki page has blocks")
    
        page_blocks_sorted = sorted(page_blocks, key=lambda b: b.get("order", 0))
    
        # 2. Find Tech Stack and Development Setup headings and verify swap
        tech_stack_order = -1
        dev_setup_order = -1
    
        for block in page_blocks_sorted:
            if block.get("type") == "heading2":
                content = block.get("content", "").lower()
                if "tech stack" in content:
                    tech_stack_order = block.get("order", 0)
                elif "development setup" in content:
                    dev_setup_order = block.get("order", 0)
    
        if tech_stack_order == -1:
            errors.append("[X] Tech Stack heading not found")
        else:
            checks_passed.append("[C] Tech Stack heading found")
        if dev_setup_order == -1:
            errors.append("[X] Development Setup heading not found")
        else:
            checks_passed.append("[C] Development Setup heading found")
    
        # After swap, Development Setup should come BEFORE Tech Stack
        if dev_setup_order > tech_stack_order:
            errors.append("[X] Sections not swapped: Development Setup should come before Tech Stack after swap")
        else:
            checks_passed.append("[C] Sections swapped: Development Setup should come before Tech Stack after swap")
    
        # 3. Find Environment Variables heading_3
        env_vars_block = None
        env_vars_order = -1
        for block in page_blocks_sorted:
            if block.get("type") == "heading3":
                content = block.get("content", "").lower()
                if "environment variables" in content:
                    env_vars_block = block
                    env_vars_order = block.get("order", 0)
                    break
    
        if not env_vars_block:
            errors.append("[X] Environment Variables heading_3 not found")
        else:
            checks_passed.append("[C] Environment Variables heading_3 found")
    
        # 4. Verify code block with bash after Environment Variables
        code_block_found = False
        code_content_valid = False
    
        for block in page_blocks_sorted:
            if block.get("type") == "code" and block.get("order", 0) > env_vars_order:
                props = block.get("properties", {})
                language = props.get("language", "").lower()
                content = block.get("content", "")
            
                if language == "bash":
                    code_block_found = True
                    # Check for required content
                    content_lower = content.lower()
                    if ("database_url" in content_lower and 
                        "api_key" in content_lower and 
                        "node_env" in content_lower):
                        code_content_valid = True
                    break
    
        if not code_block_found:
            errors.append("[X] Code block with language 'bash' not found after Environment Variables")
        else:
            checks_passed.append("[C] Code block with language 'bash' found after Environment Variables")
    
        if not code_content_valid:
            errors.append("[X] Code block missing required environment variables (DATABASE_URL, API_KEY, NODE_ENV)")
        else:
            checks_passed.append("[C] Code block has required environment variables (DATABASE_URL, API_KEY, NODE_ENV)")
    
        # 5. Verify heading_2 'Useful Commands' exists
        useful_commands_found = False
        useful_commands_order = -1
    
        for block in page_blocks_sorted:
            if block.get("type") == "heading2":
                content = block.get("content", "").lower()
                if "useful commands" in content:
                    useful_commands_found = True
                    useful_commands_order = block.get("order", 0)
                    break
    
        if not useful_commands_found:
            errors.append("[X] Missing heading_2 'Useful Commands'")
        else:
            checks_passed.append("[C] has heading_2 'Useful Commands'")
    
        # 6. Verify numbered list with npm commands after Useful Commands
        npm_commands_found = 0
        for block in page_blocks_sorted:
            if block.get("type") == "numberedList" and block.get("order", 0) > useful_commands_order:
                content = block.get("content", "").lower()
                if "npm run dev" in content or "npm test" in content or "npm run build" in content:
                    npm_commands_found += 1
    
        if npm_commands_found < 3:
            errors.append(f"[X] Expected 3 numbered list items with npm commands, found {npm_commands_found}")
        else:
            checks_passed.append(f"[C] Found 3 numbered list items with npm commands as expected")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

    # -----------------------------------------------------------------------------
    # Task: feature-requests-backlog-transformation-v2
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_feature_requests_backlog_transformation(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Feature Requests backlog transformation.
    
    Goal: Transform 'Feature Requests' page into prioritized backlog with:
    1. heading2 '🎯 Backlog Status' with callout showing completion stats
    2. heading2 '🚨 High Priority Items' for critical/urgent todos
    3. Divider
    4. heading2 '📅 Regular Backlog' for remaining items
    5. heading2 '📈 Velocity Tracking' with paragraph
    
    Validation steps (all-or-nothing):
    1. Find Feature Requests page
    2. Verify heading2 '🎯 Backlog Status' exists
    3. Verify callout with completion percentage exists
    4. Verify heading2 '🚨 High Priority Items' exists
    5. Verify divider exists
    6. Verify heading2 '📅 Regular Backlog' exists
    7. Verify heading2 '📈 Velocity Tracking' exists
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    
    # 1. Find Feature Requests page
    try:
        feature_page = _find_page_by_title(final_state_backend, "Feature Requests")
        if not feature_page:
            errors.append("[X] Feature Requests page not found")
        else:
            checks_passed.append("[C] Feature Requests page found")
    
        page_id = feature_page.get("_id")
        page_blocks = _get_blocks_for_page(final_state_backend, page_id)
    
        if not page_blocks:
            errors.append("[X] Feature Requests page has no blocks")
        else:
            checks_passed.append("[C] Feature Requests page has blocks")
    
        page_blocks_sorted = sorted(page_blocks, key=lambda b: b.get("order", 0))
    
        # 2. Verify heading2 '🎯 Backlog Status'
        backlog_status_found = False
        backlog_status_order = -1
        for block in page_blocks_sorted:
            if block.get("type") == "heading2":
                content = block.get("content", "")
                if "🎯" in content and "backlog status" in content.lower():
                    backlog_status_found = True
                    backlog_status_order = block.get("order", 0)
                    break
    
        if not backlog_status_found:
            errors.append("[X] Missing heading2 '🎯 Backlog Status'")
        else:
            checks_passed.append("[C] has heading2 '🎯 Backlog Status'")
    
        # 3. Verify callout with completion percentage after Backlog Status
        callout_found = False
        for block in page_blocks_sorted:
            if block.get("type") == "callout" and block.get("order", 0) > backlog_status_order:
                content = block.get("content", "").lower()
                props = block.get("properties", {})
                icon = props.get("icon", "")
            
                if icon == "📊" and "completion" in content and "%" in content:
                    callout_found = True
                    break
    
        if not callout_found:
            errors.append("[X] Missing callout with 📊 icon and completion percentage")
        else:
            checks_passed.append("[C] has callout with 📊 icon and completion percentage")
    
        # 4. Verify heading2 '🚨 High Priority Items'
        high_priority_found = False
        for block in page_blocks_sorted:
            if block.get("type") == "heading2":
                content = block.get("content", "")
                if "🚨" in content and "high priority" in content.lower():
                    high_priority_found = True
                    break
    
        if not high_priority_found:
            errors.append("[X] Missing heading2 '🚨 High Priority Items'")
        else:
            checks_passed.append("[C] has heading2 '🚨 High Priority Items'")
    
        # 5. Verify divider exists
        divider_found = any(b.get("type") == "divider" for b in page_blocks_sorted)
        if not divider_found:
            errors.append("[X] Missing divider block")
        else:
            checks_passed.append("[C] has divider block")
    
        # 6. Verify heading2 '📅 Regular Backlog'
        regular_backlog_found = False
        for block in page_blocks_sorted:
            if block.get("type") == "heading2":
                content = block.get("content", "")
                if "📅" in content and "regular backlog" in content.lower():
                    regular_backlog_found = True
                    break
    
        if not regular_backlog_found:
            errors.append("[X] Missing heading2 '📅 Regular Backlog'")
        else:
            checks_passed.append("[C] has heading2 '📅 Regular Backlog'")
    
        # 7. Verify heading2 '📈 Velocity Tracking'
        velocity_found = False
        for block in page_blocks_sorted:
            if block.get("type") == "heading2":
                content = block.get("content", "")
                if "📈" in content and "velocity" in content.lower():
                    velocity_found = True
                    break
    
        if not velocity_found:
            errors.append("[X] Missing heading2 '📈 Velocity Tracking'")
        else:
            checks_passed.append("[C] has heading2 '📈 Velocity Tracking'")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

    # -----------------------------------------------------------------------------
    # Task: getting-started-checklist-callouts-v2
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_getting_started_checklist_callouts(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Getting Started checklist callouts.
    
    Goal: On 'Getting Started' page, Quick Start Checklist section:
    1. Add orange callout with ⏰ icon above each unchecked todo
    2. Add divider after last todo
    3. Add paragraph with completion rate
    
    Validation steps (all-or-nothing):
    1. Find Getting Started page
    2. Verify orange callouts with ⏰ exist above unchecked todos
    3. Verify divider exists after todos
    4. Verify paragraph with completion rate exists
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    
    # 1. Find Getting Started page (page-1)
    try:
        getting_started = _find_page_by_title(final_state_backend, "Getting Started")
        if not getting_started:
            errors.append("[X] Getting Started page not found")
        else:
            checks_passed.append("[C] Getting Started page found")
    
        page_id = getting_started.get("_id")
        page_blocks = _get_blocks_for_page(final_state_backend, page_id)
    
        if not page_blocks:
            errors.append("[X] Getting Started page has no blocks")
        else:
            checks_passed.append("[C] Getting Started page has blocks")
    
        page_blocks_sorted = sorted(page_blocks, key=lambda b: b.get("order", 0))
    
        # Find Quick Start Checklist heading
        checklist_heading = None
        checklist_order = -1
        for block in page_blocks_sorted:
            if block.get("type") == "heading2":
                content = block.get("content", "").lower()
                if "quick start checklist" in content:
                    checklist_heading = block
                    checklist_order = block.get("order", 0)
                    break
    
        if not checklist_heading:
            errors.append("[X] Quick Start Checklist heading not found")
        else:
            checks_passed.append("[C] Quick Start Checklist heading found")
    
        # Find Key Features heading (section after checklist)
        key_features_order = float('inf')
        for block in page_blocks_sorted:
            if block.get("type") == "heading2":
                content = block.get("content", "").lower()
                if "key features" in content:
                    key_features_order = block.get("order", 0)
                    break
    
        # Count unchecked todos in checklist section
        unchecked_todos = []
        for block in page_blocks_sorted:
            if block.get("type") == "todo":
                order = block.get("order", 0)
                if checklist_order < order < key_features_order:
                    props = block.get("properties", {})
                    if not props.get("checked", False):
                        unchecked_todos.append(block)
    
        # 2. Verify orange callouts with ⏰ exist (should be at least equal to unchecked todos)
        orange_callouts = []
        for block in page_blocks_sorted:
            if block.get("type") == "callout":
                order = block.get("order", 0)
                if checklist_order < order < key_features_order:
                    props = block.get("properties", {})
                    bg_color = props.get("backgroundColor", "").lower()
                    icon = props.get("icon", "")
                    content = block.get("content", "").lower()
                
                    if "orange" in bg_color and icon == "⏰" and "overdue" in content:
                        orange_callouts.append(block)
    
        if len(orange_callouts) < len(unchecked_todos):
            errors.append(f"[X] Expected {len(unchecked_todos)} orange callouts with ⏰ icon for unchecked todos, found {len(orange_callouts)}")
        else:
            checks_passed.append(f"[C] Expected {len(unchecked_todos)} orange callouts with ⏰ icon for unchecked todos, found {len(orange_callouts)}")
    
        # 3. Verify divider exists between todos and Key Features
        divider_found = False
        for block in page_blocks_sorted:
            if block.get("type") == "divider":
                order = block.get("order", 0)
                if checklist_order < order < key_features_order:
                    divider_found = True
                    break
    
        if not divider_found:
            errors.append("[X] Missing divider after checklist todos")
        else:
            checks_passed.append("[C] has divider after checklist todos")
    
        # 4. Verify paragraph with completion rate
        completion_paragraph_found = False
        for block in page_blocks_sorted:
            if block.get("type") == "paragraph":
                order = block.get("order", 0)
                if checklist_order < order < key_features_order:
                    content = block.get("content", "").lower()
                    if "completion rate" in content and "%" in content:
                        completion_paragraph_found = True
                        break
    
        if not completion_paragraph_found:
            errors.append("[X] Missing paragraph with completion rate")
        else:
            checks_passed.append("[C] has paragraph with completion rate")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

    # -----------------------------------------------------------------------------
    # Task: getting-started-quick-tips
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_getting_started_quick_tips(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Getting Started quick tips.
    
    Goal: On 'Getting Started' page:
    1. Add tip paragraphs after each todo in Quick Start Checklist
    2. Add pro tip callout at end of Key Features section
    
    Validation steps (all-or-nothing):
    1. Find Getting Started page
    2. Verify tip paragraphs exist after todos (italic text with 'Tip:')
    3. Verify yellow callout with pro tip at end of Key Features
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    
    # 1. Find Getting Started page (page-1)
    try:
        getting_started = _find_page_by_title(final_state_backend, "Getting Started")
        if not getting_started:
            errors.append("[X] Getting Started page not found")
        else:
            checks_passed.append("[C] Getting Started page found")
    
        page_id = getting_started.get("_id")
        page_blocks = _get_blocks_for_page(final_state_backend, page_id)
    
        if not page_blocks:
            errors.append("[X] Getting Started page has no blocks")
        else:
            checks_passed.append("[C] Getting Started page has blocks")
    
        page_blocks_sorted = sorted(page_blocks, key=lambda b: b.get("order", 0))
    
        # Find Quick Start Checklist heading
        checklist_order = -1
        for block in page_blocks_sorted:
            if block.get("type") == "heading2":
                content = block.get("content", "").lower()
                if "quick start checklist" in content:
                    checklist_order = block.get("order", 0)
                    break
    
        if checklist_order == -1:
            errors.append("[X] Quick Start Checklist heading not found")
        else:
            checks_passed.append("[C] Quick Start Checklist heading found")
    
        # Find Key Features heading
        key_features_order = float('inf')
        for block in page_blocks_sorted:
            if block.get("type") == "heading2":
                content = block.get("content", "").lower()
                if "key features" in content:
                    key_features_order = block.get("order", 0)
                    break
    
        # 2. Verify tip paragraphs exist (should contain 'Tip:')
        tip_paragraphs = []
        for block in page_blocks_sorted:
            if block.get("type") == "paragraph":
                order = block.get("order", 0)
                if checklist_order < order < key_features_order:
                    content = block.get("content", "")
                    if "tip:" in content.lower() or "_tip:" in content.lower():
                        tip_paragraphs.append(block)
    
        # Should have 4 tip paragraphs (one for each todo)
        if len(tip_paragraphs) < 4:
            errors.append(f"[X] Expected 4 tip paragraphs after todos, found {len(tip_paragraphs)}")
        else:
            checks_passed.append(f"[C] Found 4 tip paragraphs after todos as expected")
    
        # 3. Verify yellow callout with pro tip at end of Key Features
        pro_tip_callout_found = False
        for block in page_blocks_sorted:
            if block.get("type") == "callout":
                order = block.get("order", 0)
                if order > key_features_order:
                    props = block.get("properties", {})
                    bg_color = props.get("backgroundColor", "").lower()
                    content = block.get("content", "").lower()
                
                    if "yellow" in bg_color and ("pro tip" in content or "🚀" in content):
                        pro_tip_callout_found = True
                        break
    
        if not pro_tip_callout_found:
            errors.append("[X] Missing yellow callout with pro tip at end of Key Features section")
        else:
            checks_passed.append("[C] has yellow callout with pro tip at end of Key Features section")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

    # -----------------------------------------------------------------------------
    # Task: meeting-notes-templates-summary
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_meeting_notes_templates_summary(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Meeting Notes templates and summary.
    
    Goal: On 'Meeting Notes' page:
    1. Add heading_2 '📋 Meeting Templates' after quote block
    2. Add numbered list with meeting types
    3. Add heading_3 '🎯 Best Practices'
    4. Add green callout with ✅ icon
    5. Add paragraph with action item count from child pages
    
    Validation steps (all-or-nothing):
    1. Find Meeting Notes page
    2. Verify heading_2 '📋 Meeting Templates' exists
    3. Verify numbered list with meeting types exists
    4. Verify heading_3 '🎯 Best Practices' exists
    5. Verify green callout with ✅ icon exists
    6. Verify paragraph with action item count exists
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    
    # 1. Find Meeting Notes page (page-3)
    try:
        meeting_notes = _find_page_by_title(final_state_backend, "Meeting Notes")
        if not meeting_notes:
            errors.append("[X] Meeting Notes page not found")
        else:
            checks_passed.append("[C] Meeting Notes page found")
    
        page_id = meeting_notes.get("_id")
        page_blocks = _get_blocks_for_page(final_state_backend, page_id)
    
        if not page_blocks:
            errors.append("[X] Meeting Notes page has no blocks")
        else:
            checks_passed.append("[C] Meeting Notes page has blocks")
    
        page_blocks_sorted = sorted(page_blocks, key=lambda b: b.get("order", 0))
    
        # 2. Verify heading_2 '📋 Meeting Templates'
        templates_heading_found = False
        templates_order = -1
        for block in page_blocks_sorted:
            if block.get("type") == "heading2":
                content = block.get("content", "")
                if "📋" in content and "meeting templates" in content.lower():
                    templates_heading_found = True
                    templates_order = block.get("order", 0)
                    break
    
        if not templates_heading_found:
            errors.append("[X] Missing heading_2 '📋 Meeting Templates'")
        else:
            checks_passed.append("[C] has heading_2 '📋 Meeting Templates'")
    
        # 3. Verify numbered list with meeting types
        meeting_types = ["daily standup", "sprint planning", "retrospective", "one-on-one"]
        found_types = 0
    
        for block in page_blocks_sorted:
            if block.get("type") == "numberedList" and block.get("order", 0) > templates_order:
                content = block.get("content", "").lower()
                for meeting_type in meeting_types:
                    if meeting_type in content:
                        found_types += 1
                        break
    
        if found_types < 4:
            errors.append(f"[X] Expected 4 meeting types in numbered list, found {found_types}")
        else:
            checks_passed.append(f"[C] Found 4 meeting types in numbered list as expected")
    
        # 4. Verify heading_3 '🎯 Best Practices'
        best_practices_found = False
        for block in page_blocks_sorted:
            if block.get("type") == "heading3":
                content = block.get("content", "")
                if "🎯" in content and "best practices" in content.lower():
                    best_practices_found = True
                    break
    
        if not best_practices_found:
            errors.append("[X] Missing heading_3 '🎯 Best Practices'")
        else:
            checks_passed.append("[C] has heading_3 '🎯 Best Practices'")
    
        # 5. Verify green callout with ✅ icon
        green_callout_found = False
        for block in page_blocks_sorted:
            if block.get("type") == "callout":
                props = block.get("properties", {})
                bg_color = props.get("backgroundColor", "").lower()
                icon = props.get("icon", "")
            
                if "green" in bg_color and icon == "✅":
                    green_callout_found = True
                    break
    
        if not green_callout_found:
            errors.append("[X] Missing green callout with ✅ icon")
        else:
            checks_passed.append("[C] has green callout with ✅ icon")
    
        # 6. Verify paragraph with action item count
        action_items_paragraph_found = False
        for block in page_blocks_sorted:
            if block.get("type") == "paragraph":
                content = block.get("content", "").lower()
                if "total action items" in content or ("action items" in content and "meeting" in content):
                    action_items_paragraph_found = True
                    break
    
        if not action_items_paragraph_found:
            errors.append("[X] Missing paragraph with action item count")
        else:
            checks_passed.append("[C] has paragraph with action item count")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

    # -----------------------------------------------------------------------------
    # Task: onboarding-guide-first-week-enhancement
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_onboarding_guide_first_week_enhancement(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Onboarding Guide First Week Enhancement.
    
    Goal: On 'Onboarding Guide' page, 'First Week Goals' section:
    1. Add yellow callout with 💡 icon after section heading
    2. Add divider after numbered list
    3. Add heading_3 '📝 Progress Tracking'
    4. Add 3 unchecked todo blocks
    5. Add paragraph at end with numbered list count
    
    Validation steps (all-or-nothing):
    1. Find Onboarding Guide page
    2. Find First Week Goals heading
    3. Verify yellow callout with 💡 icon after heading
    4. Verify divider exists
    5. Verify heading_3 '📝 Progress Tracking' exists
    6. Verify 3 todo blocks exist with correct text
    7. Verify paragraph with 'Total onboarding tasks' exists at end
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    
    # 1. Find Onboarding Guide page (page-13)
    try:
        onboarding_guide = _find_page_by_title(final_state_backend, "Onboarding Guide")
        if not onboarding_guide:
            errors.append("[X] Onboarding Guide page not found")
        else:
            checks_passed.append("[C] Onboarding Guide page found")
    
        page_id = onboarding_guide.get("_id")
        page_blocks = _get_blocks_for_page(final_state_backend, page_id)
    
        if not page_blocks:
            errors.append("[X] Onboarding Guide page has no blocks")
        else:
            checks_passed.append("[C] Onboarding Guide page has blocks")
    
        page_blocks_sorted = sorted(page_blocks, key=lambda b: b.get("order", 0))
    
        # 2. Find First Week Goals heading
        first_week_order = -1
        for block in page_blocks_sorted:
            if block.get("type") == "heading2":
                content = block.get("content", "").lower()
                if "first week goals" in content:
                    first_week_order = block.get("order", 0)
                    break
    
        if first_week_order == -1:
            errors.append("[X] First Week Goals heading not found")
        else:
            checks_passed.append("[C] First Week Goals heading found")
    
        # 3. Verify yellow callout with 💡 icon after heading
        yellow_callout_found = False
        for block in page_blocks_sorted:
            if block.get("type") == "callout" and block.get("order", 0) > first_week_order:
                props = block.get("properties", {})
                bg_color = props.get("backgroundColor", "").lower()
                icon = props.get("icon", "")
                content = block.get("content", "").lower()
            
                if "yellow" in bg_color and icon == "💡" and "pro tip" in content:
                    yellow_callout_found = True
                    break
    
        if not yellow_callout_found:
            errors.append("[X] Missing yellow callout with 💡 icon after First Week Goals heading")
        else:
            checks_passed.append("[C] has yellow callout with 💡 icon after First Week Goals heading")
    
        # 4. Verify divider exists
        divider_found = any(b.get("type") == "divider" for b in page_blocks_sorted if b.get("order", 0) > first_week_order)
        if not divider_found:
            errors.append("[X] Missing divider after First Week Goals section")
        else:
            checks_passed.append("[C] has divider after First Week Goals section")
    
        # 5. Verify heading_3 '📝 Progress Tracking'
        progress_tracking_found = False
        for block in page_blocks_sorted:
            if block.get("type") == "heading3":
                content = block.get("content", "")
                if "📝" in content and "progress tracking" in content.lower():
                    progress_tracking_found = True
                    break
    
        if not progress_tracking_found:
            errors.append("[X] Missing heading_3 '📝 Progress Tracking'")
        else:
            checks_passed.append("[C] has heading_3 '📝 Progress Tracking'")
    
        # 6. Verify todo blocks with correct text
        expected_todos = [
            "training modules completed",
            "met with all team members",
            "development environment ready"
        ]
    
        found_todos = 0
        for block in page_blocks_sorted:
            if block.get("type") == "todo":
                content = block.get("content", "").lower()
                for expected in expected_todos:
                    if expected in content:
                        found_todos += 1
                        break
    
        if found_todos < 3:
            errors.append(f"[X] Expected 3 progress tracking todos, found {found_todos}")
        else:
            checks_passed.append(f"[C] Found 3 progress tracking todos as expected")
    
        # 7. Verify paragraph with 'Total onboarding tasks'
        total_tasks_found = False
        for block in page_blocks_sorted:
            if block.get("type") == "paragraph":
                content = block.get("content", "").lower()
                if "total onboarding tasks" in content:
                    total_tasks_found = True
                    break
    
        if not total_tasks_found:
            errors.append("[X] Missing paragraph with 'Total onboarding tasks'")
        else:
            checks_passed.append("[C] has paragraph with 'Total onboarding tasks'")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

    # -----------------------------------------------------------------------------
    # Task: prd-overview-analytics-insertion
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_prd_overview_analytics_insertion(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate PRD Overview Analytics Insertion.
    
    Goal: On 'Comprehensive Product Requirements Document' page:
    1. Insert heading_3 '📊 Overview Analytics' between Part 2 and Part 3
    2. Add blue callout with 📈 icon
    3. Add paragraph with Part 2 statistics
    4. Add quote block with key insight
    
    Validation steps (all-or-nothing):
    1. Find PRD page
    2. Verify heading_3 '📊 Overview Analytics' exists
    3. Verify blue callout with 📈 icon exists
    4. Verify paragraph with statistics exists
    5. Verify quote block exists
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    
    # 1. Find PRD page (page-47)
    try:
        prd_page = _find_page_by_title(final_state_backend, "Comprehensive Product Requirements Document")
        if not prd_page:
            errors.append("[X] Comprehensive Product Requirements Document page not found")
        else:
            checks_passed.append("[C] Comprehensive Product Requirements Document page found")
    
        page_id = prd_page.get("_id")
        page_blocks = _get_blocks_for_page(final_state_backend, page_id)
    
        if not page_blocks:
            errors.append("[X] PRD page has no blocks")
        else:
            checks_passed.append("[C] PRD page has blocks")
    
        page_blocks_sorted = sorted(page_blocks, key=lambda b: b.get("order", 0))
    
        # 2. Verify heading_3 '📊 Overview Analytics'
        analytics_heading_found = False
        analytics_order = -1
        for block in page_blocks_sorted:
            if block.get("type") == "heading3":
                content = block.get("content", "")
                if "📊" in content and "overview analytics" in content.lower():
                    analytics_heading_found = True
                    analytics_order = block.get("order", 0)
                    break
    
        if not analytics_heading_found:
            errors.append("[X] Missing heading_3 '📊 Overview Analytics'")
        else:
            checks_passed.append("[C] has heading_3 '📊 Overview Analytics'")
    
        # 3. Verify blue callout with 📈 icon
        blue_callout_found = False
        for block in page_blocks_sorted:
            if block.get("type") == "callout" and block.get("order", 0) > analytics_order:
                props = block.get("properties", {})
                bg_color = props.get("backgroundColor", "").lower()
                icon = props.get("icon", "")
            
                if "blue" in bg_color and icon == "📈":
                    blue_callout_found = True
                    break
    
        if not blue_callout_found:
            errors.append("[X] Missing blue callout with 📈 icon")
        else:
            checks_passed.append("[C] has blue callout with 📈 icon")
    
        # 4. Verify paragraph with statistics
        stats_paragraph_found = False
        for block in page_blocks_sorted:
            if block.get("type") == "paragraph" and block.get("order", 0) > analytics_order:
                content = block.get("content", "").lower()
                if "part 2 statistics" in content or ("paragraphs" in content and "bullet" in content):
                    stats_paragraph_found = True
                    break
    
        if not stats_paragraph_found:
            errors.append("[X] Missing paragraph with Part 2 statistics")
        else:
            checks_passed.append("[C] has paragraph with Part 2 statistics")
    
        # 5. Verify quote block with key insight
        quote_found = False
        for block in page_blocks_sorted:
            if block.get("type") == "quote" and block.get("order", 0) > analytics_order:
                content = block.get("content", "").lower()
                if "key insight" in content or "overview section" in content:
                    quote_found = True
                    break
    
        if not quote_found:
            errors.append("[X] Missing quote block with key insight")
        else:
            checks_passed.append("[C] has quote block with key insight")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

    # -----------------------------------------------------------------------------
    # Task: q2-goals-objective-dashboard
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_q2_goals_objective_dashboard(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Q2 Goals Objective Dashboard.
    
    Goal: On 'Q2 Goals' page:
    1. Add heading_3 '📊 Objective Status Dashboard'
    2. Add quote block with date
    3. Add yellow callouts with 🚧 icon for each unchecked todo
    4. Add paragraph with completion rate
    
    Validation steps (all-or-nothing):
    1. Find Q2 Goals page
    2. Verify heading_3 '📊 Objective Status Dashboard' exists
    3. Verify quote block with date exists
    4. Verify yellow callouts with 🚧 icon exist
    5. Verify completion rate paragraph exists
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    
    # 1. Find Q2 Goals page (page-2-2)
    try:
        q2_goals = _find_page_by_title(final_state_backend, "Q2 Goals")
        if not q2_goals:
            errors.append("[X] Q2 Goals page not found")
        else:
            checks_passed.append("[C] Q2 Goals page found")
    
        page_id = q2_goals.get("_id")
        page_blocks = _get_blocks_for_page(final_state_backend, page_id)
    
        if not page_blocks:
            errors.append("[X] Q2 Goals page has no blocks")
        else:
            checks_passed.append("[C] Q2 Goals page has blocks")
    
        page_blocks_sorted = sorted(page_blocks, key=lambda b: b.get("order", 0))
    
        # 2. Verify heading_3 '📊 Objective Status Dashboard'
        dashboard_heading_found = False
        dashboard_order = -1
        for block in page_blocks_sorted:
            if block.get("type") == "heading3":
                content = block.get("content", "")
                if "📊" in content and "objective status dashboard" in content.lower():
                    dashboard_heading_found = True
                    dashboard_order = block.get("order", 0)
                    break
    
        if not dashboard_heading_found:
            errors.append("[X] Missing heading_3 '📊 Objective Status Dashboard'")
        else:
            checks_passed.append("[C] has heading_3 '📊 Objective Status Dashboard'")
    
        # 3. Verify quote block with date
        quote_found = False
        for block in page_blocks_sorted:
            if block.get("type") == "quote" and block.get("order", 0) > dashboard_order:
                content = block.get("content", "").lower()
                if "real-time status" in content or "status as of" in content:
                    quote_found = True
                    break
    
        if not quote_found:
            errors.append("[X] Missing quote block with date")
        else:
            checks_passed.append("[C] has quote block with date")
    
        # 4. Verify yellow callouts with 🚧 icon for unchecked todos
        yellow_callouts = []
        for block in page_blocks_sorted:
            if block.get("type") == "callout":
                props = block.get("properties", {})
                bg_color = props.get("backgroundColor", "").lower()
                icon = props.get("icon", "")
                content = block.get("content", "").lower()
            
                if "yellow" in bg_color and icon == "🚧" and "in progress" in content:
                    yellow_callouts.append(block)
    
        # Count unchecked todos in Q2 Goals
        unchecked_count = 0
        for block in page_blocks_sorted:
            if block.get("type") == "todo":
                props = block.get("properties", {})
                if not props.get("checked", False):
                    unchecked_count += 1
    
        if len(yellow_callouts) < unchecked_count:
            errors.append(f"[X] Expected {unchecked_count} yellow callouts with 🚧 icon for unchecked todos, found {len(yellow_callouts)}")
        else:
            checks_passed.append(f"[C] Expected {unchecked_count} yellow callouts with 🚧 icon for unchecked todos, found {len(yellow_callouts)}")
    
        # 5. Verify completion rate paragraph
        completion_paragraph_found = False
        for block in page_blocks_sorted:
            if block.get("type") == "paragraph":
                content = block.get("content", "").lower()
                if "completion rate" in content and "%" in content:
                    completion_paragraph_found = True
                    break
    
        if not completion_paragraph_found:
            errors.append("[X] Missing completion rate paragraph")
        else:
            checks_passed.append("[C] has completion rate paragraph")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

    # -----------------------------------------------------------------------------
    # Task: sprint-velocity-tracker
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_sprint_velocity_tracker(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Sprint Velocity Tracker page creation.
    
    Goal: Create 'Sprint Velocity Tracker' page as sibling to 'Sprint Planning - Jan 15' with:
    1. heading1 '📈 Sprint Velocity Tracker'
    2. heading2 '🏃 Current Sprint Status'
    3. heading3 '✅ Completed Stories'
    4. heading3 '🚧 In Progress Stories'
    5. heading2 '📊 Velocity Metrics' with code block
    6. heading2 '🎯 Upcoming Work' with numbered list
    7. Divider and quote
    
    Validation steps (all-or-nothing):
    1. Find Sprint Velocity Tracker page as sibling to Sprint Planning - Jan 15
    2. Verify required headings exist
    3. Verify code block with velocity metrics exists
    4. Verify divider and quote exist
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    
    # 1. Find Sprint Planning - Jan 15 to get parent
    try:
        sprint_planning = _find_page_by_title(final_state_backend, "Sprint Planning - Jan 15")
        if not sprint_planning:
            errors.append("[X] Sprint Planning - Jan 15 page not found")
        else:
            checks_passed.append("[C] Sprint Planning - Jan 15 page found")
    
        parent_id = sprint_planning.get("parentId")
    
        # 2. Find Sprint Velocity Tracker as sibling
        tracker_page = _find_page_by_title_pattern_and_parent(final_state_backend, "Sprint Velocity Tracker", parent_id)
        if not tracker_page:
            # Try finding it anywhere
            tracker_page = _find_page_by_title(final_state_backend, "Sprint Velocity Tracker")

        if not tracker_page:
            errors.append("[X] Sprint Velocity Tracker page not found")
        else:
            checks_passed.append("[C] Sprint Velocity Tracker page found")

        page_id = tracker_page.get("_id")
        page_blocks = _get_blocks_for_page(final_state_backend, page_id)
    
        if not page_blocks:
            errors.append("[X] Sprint Velocity Tracker page has no blocks")
        else:
            checks_passed.append("[C] Sprint Velocity Tracker page has blocks")
    
        page_blocks_sorted = sorted(page_blocks, key=lambda b: b.get("order", 0))
    
        # 3. Verify heading1 '📈 Sprint Velocity Tracker'
        heading1_found = False
        for block in page_blocks_sorted:
            if block.get("type") == "heading1":
                content = block.get("content", "")
                if "📈" in content and "sprint velocity tracker" in content.lower():
                    heading1_found = True
                    break
    
        if not heading1_found:
            errors.append("[X] Missing heading1 '📈 Sprint Velocity Tracker'")
        else:
            checks_passed.append("[C] has heading1 '📈 Sprint Velocity Tracker'")
    
        # 4. Verify heading2 '🏃 Current Sprint Status'
        current_sprint_found = False
        for block in page_blocks_sorted:
            if block.get("type") == "heading2":
                content = block.get("content", "")
                if "🏃" in content and "current sprint status" in content.lower():
                    current_sprint_found = True
                    break
    
        if not current_sprint_found:
            errors.append("[X] Missing heading2 '🏃 Current Sprint Status'")
        else:
            checks_passed.append("[C] has heading2 '🏃 Current Sprint Status'")
    
        # 5. Verify heading3 '✅ Completed Stories'
        completed_found = False
        for block in page_blocks_sorted:
            if block.get("type") == "heading3":
                content = block.get("content", "")
                if "✅" in content and "completed" in content.lower():
                    completed_found = True
                    break
    
        if not completed_found:
            errors.append("[X] Missing heading3 '✅ Completed Stories'")
        else:
            checks_passed.append("[C] has heading3 '✅ Completed Stories'")
    
        # 6. Verify heading3 '🚧 In Progress Stories'
        in_progress_found = False
        for block in page_blocks_sorted:
            if block.get("type") == "heading3":
                content = block.get("content", "")
                if "🚧" in content and "in progress" in content.lower():
                    in_progress_found = True
                    break
    
        if not in_progress_found:
            errors.append("[X] Missing heading3 '🚧 In Progress Stories'")
        else:
            checks_passed.append("[C] has heading3 '🚧 In Progress Stories'")
    
        # 7. Verify heading2 '📊 Velocity Metrics'
        velocity_metrics_found = False
        velocity_metrics_order = -1
        for block in page_blocks_sorted:
            if block.get("type") == "heading2":
                content = block.get("content", "")
                if "📊" in content and "velocity metrics" in content.lower():
                    velocity_metrics_found = True
                    velocity_metrics_order = block.get("order", 0)
                    break
    
        if not velocity_metrics_found:
            errors.append("[X] Missing heading2 '📊 Velocity Metrics'")
        else:
            checks_passed.append("[C] has heading2 '📊 Velocity Metrics'")
    
        # 8. Verify code block with velocity data
        code_block_found = False
        for block in page_blocks_sorted:
            if block.get("type") == "code" and block.get("order", 0) > velocity_metrics_order:
                content = block.get("content", "").lower()
                if "sprint" in content and "%" in content:
                    code_block_found = True
                    break
    
        if not code_block_found:
            errors.append("[X] Missing code block with velocity metrics")
        else:
            checks_passed.append("[C] has code block with velocity metrics")
    
        # 9. Verify heading2 '🎯 Upcoming Work'
        upcoming_work_found = False
        for block in page_blocks_sorted:
            if block.get("type") == "heading2":
                content = block.get("content", "")
                if "🎯" in content and "upcoming work" in content.lower():
                    upcoming_work_found = True
                    break
    
        if not upcoming_work_found:
            errors.append("[X] Missing heading2 '🎯 Upcoming Work'")
        else:
            checks_passed.append("[C] has heading2 '🎯 Upcoming Work'")
    
        # 10. Verify divider and quote
        divider_found = any(b.get("type") == "divider" for b in page_blocks_sorted)
        if not divider_found:
            errors.append("[X] Missing divider block")
        else:
            checks_passed.append("[C] has divider block")
    
        quote_found = False
        for block in page_blocks_sorted:
            if block.get("type") == "quote":
                content = block.get("content", "").lower()
                if "velocity" in content or "sustainable" in content or "progress" in content:
                    quote_found = True
                    break
    
        if not quote_found:
            errors.append("[X] Missing quote block about velocity")
        else:
            checks_passed.append("[C] has quote block about velocity")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

    # -----------------------------------------------------------------------------
    # Task: team-related-documentation-index
    # -----------------------------------------------------------------------------
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_agent_team_related_documentation_index(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Team-Related Documentation Index page creation.
    
    Goal: Create '👥 Team-Related Documentation Index' page at root level with:
    1. heading_1 '👥 Cross-Team Documentation Map'
    2. Paragraph explaining the index
    3. heading_2 for each page found with team headings
    4. Bulleted list of team-related headings
    5. Divider
    6. heading_2 '📊 Statistics'
    7. Blue callout with totals
    
    Validation steps (all-or-nothing):
    1. Find Team-Related Documentation Index page at root level
    2. Verify heading_1 '👥 Cross-Team Documentation Map' exists
    3. Verify intro paragraph exists
    4. Verify heading_2 entries exist
    5. Verify bulleted list items with heading info exist
    6. Verify divider exists
    7. Verify heading_2 '📊 Statistics' exists
    8. Verify blue callout with totals exists
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    
    # 1. Find Team-Related Documentation Index page
    try:
        index_result = final_state_backend.query({
            "collection": "pages",
            "filter": {"title": {"$regex": "team-related documentation index|cross-team documentation", "$options": "i"}}
        })
        index_page = index_result[0] if isinstance(index_result, list) and index_result else None
        if not index_page:
            errors.append("[X] Team-Related Documentation Index page not found")
        else:
            checks_passed.append("[C] Team-Related Documentation Index page found")

        page_id = index_page.get("_id")
        page_blocks = _get_blocks_for_page(final_state_backend, page_id)
    
        if not page_blocks:
            errors.append("[X] Team-Related Documentation Index page has no blocks")
        else:
            checks_passed.append("[C] Team-Related Documentation Index page has blocks")
    
        page_blocks_sorted = sorted(page_blocks, key=lambda b: b.get("order", 0))
    
        # 2. Verify heading_1 '👥 Cross-Team Documentation Map'
        heading1_found = False
        for block in page_blocks_sorted:
            if block.get("type") == "heading1":
                content = block.get("content", "")
                if "👥" in content and ("cross-team" in content.lower() or "team" in content.lower()):
                    heading1_found = True
                    break
    
        if not heading1_found:
            errors.append("[X] Missing heading_1 with '👥 Cross-Team Documentation Map'")
        else:
            checks_passed.append("[C] has heading_1 with '👥 Cross-Team Documentation Map'")
    
        # 3. Verify intro paragraph
        intro_paragraph_found = False
        for block in page_blocks_sorted:
            if block.get("type") == "paragraph":
                content = block.get("content", "").lower()
                if "index" in content or "aggregates" in content or "team-related content" in content:
                    intro_paragraph_found = True
                    break
    
        if not intro_paragraph_found:
            errors.append("[X] Missing intro paragraph explaining the index")
        else:
            checks_passed.append("[C] has intro paragraph explaining the index")
    
        # 4. Verify heading_2 entries for pages exist (at least one)
        page_headings = []
        for block in page_blocks_sorted:
            if block.get("type") == "heading2":
                content = block.get("content", "")
                if "📊" not in content:  # Exclude Statistics heading
                    page_headings.append(block)
    
        if len(page_headings) < 1:
            errors.append("[X] Missing heading_2 entries for found pages")
        else:
            checks_passed.append("[C] has heading_2 entries for found pages")
    
        # 5. Verify bulleted list items with heading info
        bullet_with_type = False
        for block in page_blocks_sorted:
            if block.get("type") == "bulletedList":
                content = block.get("content", "").lower()
                if "(type:" in content or "heading1" in content or "heading2" in content or "heading3" in content:
                    bullet_with_type = True
                    break
    
        if not bullet_with_type:
            errors.append("[X] Missing bulleted list items with heading type info")
        else:
            checks_passed.append("[C] has bulleted list items with heading type info")
    
        # 6. Verify divider exists
        divider_found = any(b.get("type") == "divider" for b in page_blocks_sorted)
        if not divider_found:
            errors.append("[X] Missing divider block")
        else:
            checks_passed.append("[C] has divider block")
    
        # 7. Verify heading_2 '📊 Statistics'
        stats_heading_found = False
        stats_order = -1
        for block in page_blocks_sorted:
            if block.get("type") == "heading2":
                content = block.get("content", "")
                if "📊" in content and "statistics" in content.lower():
                    stats_heading_found = True
                    stats_order = block.get("order", 0)
                    break
    
        if not stats_heading_found:
            errors.append("[X] Missing heading_2 '📊 Statistics'")
        else:
            checks_passed.append("[C] has heading_2 '📊 Statistics'")
    
        # 8. Verify blue callout with totals
        blue_callout_found = False
        for block in page_blocks_sorted:
            if block.get("type") == "callout" and block.get("order", 0) > stats_order:
                props = block.get("properties", {})
                bg_color = props.get("backgroundColor", "").lower()
                content = block.get("content", "").lower()
            
                if "blue" in bg_color and ("total pages" in content or "total team" in content):
                    blue_callout_found = True
                    break
    
        if not blue_callout_found:
            errors.append("[X] Missing blue callout with totals under Statistics")
        else:
            checks_passed.append("[C] has blue callout with totals under Statistics")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_meeting_hub_creation(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate Meeting Hub task completion.
    
    Verification:
    - Meeting Hub page exists with calendar icon and 3 main sections
    - 2 template sub-pages created with structured content (agenda, participants, notes headings)
    - Meeting Hub marked as favorite
    - At least 6 heading blocks total across all pages
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    # 1. Find page with "Meeting Hub" in title
    try:
        meeting_hub = _find_page_by_title(final_state_backend, "Meeting Hub")
        if not meeting_hub:
            errors.append("[X] Meeting Hub page not found")
        else:
            checks_passed.append("[C] Meeting Hub page found")
    
        meeting_hub_id = meeting_hub.get("_id")
    
        # 2. Check Meeting Hub has calendar icon
        icon = meeting_hub.get("icon")
        if not _is_calendar_icon(icon):
            errors.append(f"[X] Meeting Hub does not have a calendar icon (found: '{icon}')")
        else:
            checks_passed.append(f"[C] Meeting Hub has a calendar icon (found: '{icon}')")
    
        # 3. Check Meeting Hub isFavorite == true
        if not meeting_hub.get("isFavorite"):
            errors.append("[X] Meeting Hub is not marked as favorite")
        else:
            checks_passed.append("[C] Meeting Hub is marked as favorite")
    
        # 4. Query pages with parentId == Meeting Hub._id
        child_pages = _get_child_pages(final_state_backend, meeting_hub_id)
        if len(child_pages) < 2:
            errors.append(f"[X] Meeting Hub has fewer than 2 sub-pages (found: {len(child_pages)})")
        else:
            checks_passed.append(f"[C] Meeting Hub has fewer than 2 sub-pages (found: {len(child_pages)})")
    
        # 6. Check sub-page titles contain "Sprint Planning" and "Project Kickoff"
        child_titles = [p.get("title", "").lower() for p in child_pages]
        has_sprint_planning = any("sprint planning" in t for t in child_titles)
        has_project_kickoff = any("project kickoff" in t for t in child_titles)
    
        if not has_sprint_planning:
            errors.append("[X] Sprint Planning Template sub-page not found")
        else:
            checks_passed.append("[C] Sprint Planning Template sub-page found")
        if not has_project_kickoff:
            errors.append("[X] Project Kickoff Template sub-page not found")
        else:
            checks_passed.append("[C] Project Kickoff Template sub-page found")
    
        # 5. Count heading blocks for Meeting Hub
        meeting_hub_blocks = _get_blocks_for_page(final_state_backend, meeting_hub_id)
        meeting_hub_headings = _count_heading_blocks(meeting_hub_blocks)
    
        # Check for the 3 required section headings in Meeting Hub
        meeting_hub_heading_contents = [
            b.get("content", "").lower() 
            for b in meeting_hub_blocks 
            if b.get("type") in {"heading1", "heading2", "heading3"}
        ]
    
        has_upcoming = any("upcoming" in c and "meeting" in c for c in meeting_hub_heading_contents)
        has_templates = any("template" in c for c in meeting_hub_heading_contents)
        has_archive = any("archive" in c for c in meeting_hub_heading_contents)
    
        if not (has_upcoming and has_templates and has_archive):
            missing = []
            if not has_upcoming:
                missing.append("Upcoming Meetings")
            if not has_templates:
                missing.append("Meeting Templates")
            if not has_archive:
                missing.append("Archive")
            errors.append(f"[X] Meeting Hub missing section headings: {', '.join(missing)}")
        else:
            checks_passed.append(f"[C] Meeting Hub has section headings")
    
        # 9. Count heading blocks for each template page
        total_headings = meeting_hub_headings
    
        for child_page in child_pages:
            child_id = child_page.get("_id")
            child_title = child_page.get("title", "").lower()
        
            # Only check the Sprint Planning and Project Kickoff templates
            if "sprint planning" in child_title or "project kickoff" in child_title:
                child_blocks = _get_blocks_for_page(final_state_backend, child_id)
                child_heading_count = _count_heading_blocks(child_blocks)
                total_headings += child_heading_count
            
                # Check each template has agenda, participants, notes headings
                child_heading_contents = [
                    b.get("content", "").lower() 
                    for b in child_blocks 
                    if b.get("type") in {"heading1", "heading2", "heading3"}
                ]
            
                has_agenda = any("agenda" in c for c in child_heading_contents)
                has_participants = any("participant" in c for c in child_heading_contents)
                has_notes = any("note" in c for c in child_heading_contents)
            
                if not (has_agenda and has_participants and has_notes):
                    missing = []
                    if not has_agenda:
                        missing.append("Agenda")
                    if not has_participants:
                        missing.append("Participants")
                    if not has_notes:
                        missing.append("Notes")
                    errors.append(f"[X] Template '{child_page.get('title')}' missing headings: {', '.join(missing)}")
                else:
                    checks_passed.append(f"[C] Template '{child_page.get('title')}' has headings")
    
        # 10. Verify total heading count >= 6
        if total_headings < 6:
            errors.append(f"[X] Total heading blocks across all pages is {total_headings}, expected at least 6")
        else:
            checks_passed.append(f"[C] Total heading blocks across all pages is {total_headings}, expected at least 6")
    
        # 11. All checks passed
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_new_hire_onboarding_creation(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate New Hire Onboarding task completion.
    
    Verification:
    - Page titled 'New Hire Onboarding' exists with graduation cap icon
    - Page is a child of 'Team Directory'
    - Contains 3 sections: 'First Week Checklist', 'Resources & Links', 'Team Contacts'
    - Includes todo items, bulleted lists, and callout blocks in new sections
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    # 1. Find page with "New Hire Onboarding" in title
    try:
        onboarding_page = _find_page_by_title(final_state_backend, "New Hire Onboarding")
        if not onboarding_page:
            errors.append("[X] New Hire Onboarding page not found")
        else:
            checks_passed.append("[C] New Hire Onboarding page found")
    
        onboarding_page_id = onboarding_page.get("_id")
    
        # 2. Check page has graduation cap icon
        icon = onboarding_page.get("icon")
        if not _is_graduation_cap_icon(icon):
            errors.append(f"[X] New Hire Onboarding does not have a graduation cap icon (found: '{icon}')")
        else:
            checks_passed.append(f"[C] New Hire Onboarding has a graduation cap icon (found: '{icon}')")
    
        # 3. Get the parent page and verify it's named "Team Directory"
        parent_id = onboarding_page.get("parentId")
        if not parent_id:
            errors.append("[X] New Hire Onboarding has no parent page")
        else:
            checks_passed.append("[C] New Hire Onboarding has parent page")
    
        parent_page = _find_page_by_id(final_state_backend, parent_id)
        if not parent_page:
            errors.append(f"[X] Parent page with id '{parent_id}' not found")
        else:
            checks_passed.append(f"[C] Parent page with id '{parent_id}' found")
    
        # 4. Check if parent page is named "Team Directory"
        parent_title = parent_page.get("title", "").lower()
        if "team directory" not in parent_title:
            errors.append(f"[X] New Hire Onboarding parent is not Team Directory (parent title: '{parent_page.get('title')}')")
        else:
            checks_passed.append(f"[C] New Hire Onboarding parent is Team Directory (parent title: '{parent_page.get('title')}')")
    
        # 5. Query blocks for New Hire Onboarding page
        page_blocks = _get_blocks_for_page(final_state_backend, onboarding_page_id)
    
        # 6. Check for 3 required section headings
        heading_contents = [
            b.get("content", "").lower() 
            for b in page_blocks 
            if b.get("type") in {"heading1", "heading2", "heading3"}
        ]
    
        has_first_week = any("first week" in c and "checklist" in c for c in heading_contents)
        has_resources = any(("resources" in c and "links" in c) or ("resources" in c and "link" in c) for c in heading_contents)
        has_team_contacts = any("team" in c and "contact" in c for c in heading_contents)
    
        if not (has_first_week and has_resources and has_team_contacts):
            missing = []
            if not has_first_week:
                missing.append("First Week Checklist")
            if not has_resources:
                missing.append("Resources & Links")
            if not has_team_contacts:
                missing.append("Team Contacts")
            errors.append(f"[X] New Hire Onboarding missing section headings: {', '.join(missing)}")
        else:
            checks_passed.append(f"[C] New Hire Onboarding has section headings")
    
        # 7. Check for required block types: todo, bulletedList, callout
        if not _has_block_type(page_blocks, "todo"):
            errors.append("[X] New Hire Onboarding page has no todo blocks")
        else:
            checks_passed.append("[C] New Hire Onboarding page has todo blocks")
    
        if not _has_block_type(page_blocks, "bulletedList"):
            errors.append("[X] New Hire Onboarding page has no bulletedList blocks")
        else:
            checks_passed.append("[C] New Hire Onboarding page has bulletedList blocks")
    
        if not _has_block_type(page_blocks, "callout"):
            errors.append("[X] New Hire Onboarding page has no callout blocks")
        else:
            checks_passed.append("[C] New Hire Onboarding page has callout blocks")
    
        # 9. All checks passed
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_weekly_planning_template_creation(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate Weekly Planning Template task completion.
    
    Verification:
    - New page 'Weekly Planning Template' exists with calendar icon and is favorited
    - Contains 3 heading2 sections with specified titles
    - Each section has a numbered list below it
    - Original template remains unchanged
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    # 1. Query all pages from backend
    # 2. Find page with "Weekly Planning Template" in title
    try:
        planning_template = _find_page_by_title(final_state_backend, "Weekly Planning Template")
        if not planning_template:
            errors.append("[X] Weekly Planning Template page not found")
        else:
            checks_passed.append("[C] Weekly Planning Template page found")
    
        planning_template_id = planning_template.get("_id")
    
        # 3. Check page has calendar icon
        icon = planning_template.get("icon")
        if not _is_calendar_icon(icon):
            errors.append(f"[X] Weekly Planning Template does not have a calendar icon (found: '{icon}')")
        else:
            checks_passed.append(f"[C] Weekly Planning Template has a calendar icon (found: '{icon}')")
    
        # 4. Check page isFavorite == true
        if not planning_template.get("isFavorite"):
            errors.append("[X] Weekly Planning Template is not marked as favorite")
        else:
            checks_passed.append("[C] Weekly Planning Template is marked as favorite")
    
        # 5. Query all blocks for Weekly Planning Template page
        page_blocks = _get_blocks_for_page(final_state_backend, planning_template_id)
    
        # 6. Find heading2 blocks and check for 3 required sections
        heading2_contents = [
            b.get("content", "").lower() 
            for b in page_blocks 
            if b.get("type") == "heading2"
        ]
    
        has_goals = any("goals" in c and "week" in c for c in heading2_contents)
        has_blockers = any("blocker" in c for c in heading2_contents)
        has_next_week = any("next" in c and "week" in c and "preview" in c for c in heading2_contents)
    
        if not (has_goals and has_blockers and has_next_week):
            missing = []
            if not has_goals:
                missing.append("Goals This Week")
            if not has_blockers:
                missing.append("Blockers")
            if not has_next_week:
                missing.append("Next Week Preview")
            errors.append(f"[X] Weekly Planning Template missing heading2 sections: {', '.join(missing)}")
        else:
            checks_passed.append(f"[C] Weekly Planning Template has heading2 sections")
    
        # 7. Count numberedList blocks - need at least 3 (one per section)
        numbered_list_count = _count_blocks_of_type(page_blocks, "numberedList")
        if numbered_list_count < 3:
            errors.append(f"[X] Weekly Planning Template has {numbered_list_count} numbered lists, expected at least 3")
        else:
            checks_passed.append(f"[C] Weekly Planning Template has {numbered_list_count} numbered lists, expected at least 3")
    
        # 8. Find "Weekly Standup Template" page - should still exist
        standup_template = _find_page_by_title(final_state_backend, "Weekly Standup Template")
        if not standup_template:
            errors.append("[X] Original Weekly Standup Template page was deleted or not found")
        else:
            checks_passed.append("[C] Original Weekly Standup Template page was deleted or found")
    
        # 9. Check original template still has clipboard icon "📋"
        original_icon = standup_template.get("icon")
        if original_icon != "📋":
            errors.append(f"[X] Original Weekly Standup Template icon was changed (found: '{original_icon}', expected: '📋')")
        else:
            checks_passed.append(f"[C] Original Weekly Standup Template icon was changed (found: '{original_icon}', expected: '📋')")
    
        # 10. All checks passed
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_documentation_templates_creation(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate Documentation Templates task completion.
    
    Verification:
    - New page 'Documentation Templates' exists with document icon and is marked as favorite
    - Contains 3 template pages as children (API Template plus 2 new templates)
    - Each template page contains heading, code, and callout blocks
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    # 1. Query all pages from backend
    # 2. Find page with "Documentation Templates" in title
    try:
        doc_templates = _find_page_by_title(final_state_backend, "Documentation Templates")
        if not doc_templates:
            errors.append("[X] Documentation Templates page not found")
        else:
            checks_passed.append("[C] Documentation Templates page found")
    
        doc_templates_id = doc_templates.get("_id")
    
        # 3. Check page has document icon
        icon = doc_templates.get("icon")
        if not _is_document_icon(icon):
            errors.append(f"[X] Documentation Templates does not have a document icon (found: '{icon}')")
        else:
            checks_passed.append(f"[C] Documentation Templates has a document icon (found: '{icon}')")
    
        # 4. Check page isFavorite == true
        if not doc_templates.get("isFavorite"):
            errors.append("[X] Documentation Templates is not marked as favorite")
        else:
            checks_passed.append("[C] Documentation Templates is marked as favorite")
    
        # 5. Query pages with parentId == Documentation Templates._id
        child_pages = _get_child_pages(final_state_backend, doc_templates_id)
        if len(child_pages) < 3:
            errors.append(f"[X] Documentation Templates has fewer than 3 child pages (found: {len(child_pages)})")
        else:
            checks_passed.append(f"[C] Documentation Templates has fewer than 3 child pages (found: {len(child_pages)})")
    
        # 6. Check child page titles include required templates
        child_titles = [p.get("title", "").lower() for p in child_pages]
        has_api_template = any("api" in t and "template" in t for t in child_titles)
        has_tech_spec = any("technical" in t and "spec" in t and "template" in t for t in child_titles)
        has_tutorial = any("tutorial" in t and "template" in t for t in child_titles)
    
        if not has_api_template:
            errors.append("[X] API Template child page not found")
        else:
            checks_passed.append("[C] API Template child page found")
        if not has_tech_spec:
            errors.append("[X] Technical Spec Template child page not found")
        else:
            checks_passed.append("[C] Technical Spec Template child page found")
        if not has_tutorial:
            errors.append("[X] Tutorial Template child page not found")
        else:
            checks_passed.append("[C] Tutorial Template child page found")
    
        # 7. Query all blocks from backend
    
        # 8. For each template page, check for required block types
        template_names = ["api", "technical", "tutorial"]
    
        for child_page in child_pages:
            child_title = child_page.get("title", "").lower()
            child_id = child_page.get("_id")
        
            # Only check the required template pages
            is_required_template = any(
                name in child_title and "template" in child_title 
                for name in template_names
            )
        
            if is_required_template:
                page_blocks = _get_blocks_for_page(final_state_backend, child_id)
            
                # Check for at least 1 heading block
                if not _has_heading_block(page_blocks):
                    errors.append(f"[X] Template '{child_page.get('title')}' has no heading blocks")
                else:
                    checks_passed.append(f"[C] Template '{child_page.get('title')}' has heading blocks")
            
                # Check for at least 1 code block
                if not _has_block_type(page_blocks, "code"):
                    errors.append(f"[X] Template '{child_page.get('title')}' has no code blocks")
                else:
                    checks_passed.append(f"[C] Template '{child_page.get('title')}' has code blocks")
            
                # Check for at least 1 callout block
                if not _has_block_type(page_blocks, "callout"):
                    errors.append(f"[X] Template '{child_page.get('title')}' has no callout blocks")
                else:
                    checks_passed.append(f"[C] Template '{child_page.get('title')}' has callout blocks")
    
        # 9. All checks passed
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_knowledge_base_creation(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate Knowledge Base task completion.
    
    Verification:
    - New page 'Best Practices Wiki' with lightbulb icon created
    - New parent 'Knowledge Base' with brain icon and favorite status
    - Best practices wiki contains: 3 heading1 blocks, 3 bulletedList blocks, 
      at least 2 todo blocks, and 2 divider blocks
    - Both wiki pages moved under Knowledge Base parent
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    # 1. Query all pages from backend
    # 2. Find "Knowledge Base" page
    try:
        knowledge_base = _find_page_by_title(final_state_backend, "Knowledge Base")
        if not knowledge_base:
            errors.append("[X] Knowledge Base page not found")
        else:
            checks_passed.append("[C] Knowledge Base page found")
    
        knowledge_base_id = knowledge_base.get("_id")
    
        # 3. Check Knowledge Base has brain icon
        icon = knowledge_base.get("icon")
        if not _is_brain_icon(icon):
            errors.append(f"[X] Knowledge Base does not have a brain icon (found: '{icon}')")
        else:
            checks_passed.append(f"[C] Knowledge Base has a brain icon (found: '{icon}')")
    
        # 4. Check Knowledge Base isFavorite == true
        if not knowledge_base.get("isFavorite"):
            errors.append("[X] Knowledge Base is not marked as favorite")
        else:
            checks_passed.append("[C] Knowledge Base is marked as favorite")
    
        # 5. Find "Best Practices Wiki" page
        best_practices = _find_page_by_title(final_state_backend, "Best Practices Wiki")
        if not best_practices:
            errors.append("[X] Best Practices Wiki page not found")
        else:
            checks_passed.append("[C] Best Practices Wiki page found")
    
        best_practices_id = best_practices.get("_id")
    
        # 6. Check Best Practices Wiki has lightbulb icon
        bp_icon = best_practices.get("icon")
        if not _is_lightbulb_icon(bp_icon):
            errors.append(f"[X] Best Practices Wiki does not have a lightbulb icon (found: '{bp_icon}')")
        else:
            checks_passed.append(f"[C] Best Practices Wiki has a lightbulb icon (found: '{bp_icon}')")
    
        # 7. Check Best Practices Wiki has parentId == Knowledge Base._id
        if best_practices.get("parentId") != knowledge_base_id:
            errors.append(f"[X] Best Practices Wiki is not under Knowledge Base (parentId: '{best_practices.get('parentId')}')")
        else:
            checks_passed.append(f"[C] Best Practices Wiki is under Knowledge Base (parentId: '{best_practices.get('parentId')}')")
    
        # 8. Find "Engineering Wiki" page specifically under Knowledge Base
        engineering_wiki = _find_page_by_title_pattern_and_parent(final_state_backend, "Engineering Wiki", knowledge_base_id)
        if not engineering_wiki:
            # Fallback: check if any Engineering Wiki exists but with wrong parent
            any_eng_wiki = _find_page_by_title(final_state_backend, "Engineering Wiki")
            if any_eng_wiki:
                errors.append(f"[X] Engineering Wiki exists but is not under Knowledge Base (parentId: '{any_eng_wiki.get('parentId')}')")
            else:
                checks_passed.append(f"[C] Engineering Wiki exists but is under Knowledge Base (parentId: '{any_eng_wiki.get('parentId')}')")
            errors.append("[X] Engineering Wiki page not found")
        else:
            checks_passed.append("[C] Engineering Wiki page found")
    
        # 9. Query all blocks from backend
    
        # 10. Get blocks for Best Practices Wiki page
        bp_blocks = _get_blocks_for_page(final_state_backend, best_practices_id)
    
        # 11. Count specific block types for Best Practices Wiki
        heading1_count = _count_blocks_of_type(bp_blocks, "heading1")
        if heading1_count < 3:
            errors.append(f"[X] Best Practices Wiki has {heading1_count} heading1 blocks, expected at least 3")
        else:
            checks_passed.append(f"[C] Best Practices Wiki has {heading1_count} heading1 blocks, expected at least 3")
    
        bulleted_list_count = _count_blocks_of_type(bp_blocks, "bulletedList")
        if bulleted_list_count < 3:
            errors.append(f"[X] Best Practices Wiki has {bulleted_list_count} bulletedList blocks, expected at least 3")
        else:
            checks_passed.append(f"[C] Best Practices Wiki has {bulleted_list_count} bulletedList blocks, expected at least 3")
    
        todo_count = _count_blocks_of_type(bp_blocks, "todo")
        if todo_count < 2:
            errors.append(f"[X] Best Practices Wiki has {todo_count} todo blocks, expected at least 2")
        else:
            checks_passed.append(f"[C] Best Practices Wiki has {todo_count} todo blocks, expected at least 2")
    
        divider_count = _count_blocks_of_type(bp_blocks, "divider")
        if divider_count < 2:
            errors.append(f"[X] Best Practices Wiki has {divider_count} divider blocks, expected at least 2")
        else:
            checks_passed.append(f"[C] Best Practices Wiki has {divider_count} divider blocks, expected at least 2")
    
        # 12. All checks passed
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_team_hub_creation(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate Team Hub task completion.
    
    Verification:
    - Team Hub exists with people icon
    - Team Directory moved under hub
    - 2 additional sub-pages created (Team Roles, Contact Info)
    - Hub contains welcome message, navigation bullets, and colored callout with guidelines
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    # 1. Query all pages from backend
    # 2. Find "Team Hub" page
    try:
        team_hub = _find_page_by_title(final_state_backend, "Team Hub")
        if not team_hub:
            errors.append("[X] Team Hub page not found")
        else:
            checks_passed.append("[C] Team Hub page found")
    
        team_hub_id = team_hub.get("_id")
    
        # 3. Check Team Hub has people icon
        icon = team_hub.get("icon")
        if not _is_people_icon(icon):
            errors.append(f"[X] Team Hub does not have a people icon (found: '{icon}')")
        else:
            checks_passed.append(f"[C] Team Hub has a people icon (found: '{icon}')")
    
        # 4. Find "Team Directory" page under Team Hub
        team_directory = _find_page_by_title_pattern_and_parent(final_state_backend, "Team Directory", team_hub_id)
        if not team_directory:
            # Fallback: check if any Team Directory exists but with wrong parent
            any_dir = _find_page_by_title(final_state_backend, "Team Directory")
            if any_dir:
                errors.append(f"[X] Team Directory exists but is not under Team Hub (parentId: '{any_dir.get('parentId')}')")
            else:
                checks_passed.append(f"[C] Team Directory exists but is under Team Hub (parentId: '{any_dir.get('parentId')}')")
            errors.append("[X] Team Directory page not found")
        else:
            checks_passed.append("[C] Team Directory page found")

        # 5. Find "Team Roles" page under Team Hub
        team_roles = _find_page_by_title_pattern_and_parent(final_state_backend, "Team Roles", team_hub_id)
        if not team_roles:
            # Fallback: check if any Team Roles exists but with wrong parent
            any_roles = _find_page_by_title(final_state_backend, "Team Roles")
            if any_roles:
                errors.append(f"[X] Team Roles exists but is not under Team Hub (parentId: '{any_roles.get('parentId')}')")
            else:
                checks_passed.append(f"[C] Team Roles exists but is under Team Hub (parentId: '{any_roles.get('parentId')}')")
            errors.append("[X] Team Roles page not found")
        else:
            checks_passed.append("[C] Team Roles page found")

        # 6. Find "Contact Info" page under Team Hub
        contact_info = _find_page_by_title_pattern_and_parent(final_state_backend, "Contact Info", team_hub_id)
        if not contact_info:
            # Fallback: check if any Contact Info exists but with wrong parent
            any_contact = _find_page_by_title(final_state_backend, "Contact Info")
            if any_contact:
                errors.append(f"[X] Contact Info exists but is not under Team Hub (parentId: '{any_contact.get('parentId')}')")
            else:
                checks_passed.append(f"[C] Contact Info exists but is under Team Hub (parentId: '{any_contact.get('parentId')}')")
            errors.append("[X] Contact Info page not found")
        else:
            checks_passed.append("[C] Contact Info page found")
    
        # 10. Query all blocks from backend
    
        # 11. Get blocks for Team Hub page
        hub_blocks = _get_blocks_for_page(final_state_backend, team_hub_id)
    
        # 12. Check for required block types
        # Check for at least 1 paragraph block (welcome message)
        if not _has_block_type(hub_blocks, "paragraph"):
            errors.append("[X] Team Hub has no paragraph blocks (welcome message)")
        else:
            checks_passed.append("[C] Team Hub has paragraph blocks (welcome message)")
    
        # Check for at least 1 bulletedList block (navigation)
        if not _has_block_type(hub_blocks, "bulletedList"):
            errors.append("[X] Team Hub has no bulletedList blocks (navigation)")
        else:
            checks_passed.append("[C] Team Hub has bulletedList blocks (navigation)")
    
        # Check for at least 1 callout block (guidelines)
        if not _has_block_type(hub_blocks, "callout"):
            errors.append("[X] Team Hub has no callout blocks (guidelines)")
        else:
            checks_passed.append("[C] Team Hub has callout blocks (guidelines)")
    
        # 13. All checks passed
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_engineering_docs_hub_creation(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate Engineering Docs Hub task completion.
    
    Verification:
    - Page 'Engineering Docs Hub' with gear icon exists
    - Has at least 3 child pages including moved engineering pages and 2 new sub-pages
    - 'Development Guidelines' and 'Code Review Process' each contain headings, paragraphs,
      code blocks, and bulleted lists
    - Hub page contains numbered list table of contents
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    # 1. Query all pages from backend
    # 2. Find "Engineering Docs Hub" page
    try:
        eng_hub = _find_page_by_title(final_state_backend, "Engineering Docs Hub")
        if not eng_hub:
            errors.append("[X] Engineering Docs Hub page not found")
        else:
            checks_passed.append("[C] Engineering Docs Hub page found")
    
        eng_hub_id = eng_hub.get("_id")
    
        # 3. Check hub has gear icon
        icon = eng_hub.get("icon")
        if not _is_gear_icon(icon):
            errors.append(f"[X] Engineering Docs Hub does not have a gear icon (found: '{icon}')")
        else:
            checks_passed.append(f"[C] Engineering Docs Hub has a gear icon (found: '{icon}')")
    
        # 4. Get child pages with parentId == Hub._id
        child_pages = _get_child_pages(final_state_backend, eng_hub_id)
        if len(child_pages) < 3:
            errors.append(f"[X] Engineering Docs Hub has fewer than 3 child pages (found: {len(child_pages)})")
        else:
            checks_passed.append(f"[C] Engineering Docs Hub has fewer than 3 child pages (found: {len(child_pages)})")
    
        # 5. Find "Development Guidelines" page
        dev_guidelines = _find_page_by_title(final_state_backend, "Development Guidelines")
        if not dev_guidelines:
            errors.append("[X] Development Guidelines page not found")
        else:
            checks_passed.append("[C] Development Guidelines page found")
    
        dev_guidelines_id = dev_guidelines.get("_id")
    
        # 6. Check Development Guidelines parentId == Hub._id
        if dev_guidelines.get("parentId") != eng_hub_id:
            errors.append(f"[X] Development Guidelines is not under Engineering Docs Hub (parentId: '{dev_guidelines.get('parentId')}')")
        else:
            checks_passed.append(f"[C] Development Guidelines is under Engineering Docs Hub (parentId: '{dev_guidelines.get('parentId')}')")
    
        # 7. Find "Code Review Process" page
        code_review = _find_page_by_title(final_state_backend, "Code Review Process")
        if not code_review:
            errors.append("[X] Code Review Process page not found")
        else:
            checks_passed.append("[C] Code Review Process page found")
    
        code_review_id = code_review.get("_id")
    
        # 8. Check Code Review Process parentId == Hub._id
        if code_review.get("parentId") != eng_hub_id:
            errors.append(f"[X] Code Review Process is not under Engineering Docs Hub (parentId: '{code_review.get('parentId')}')")
        else:
            checks_passed.append(f"[C] Code Review Process is under Engineering Docs Hub (parentId: '{code_review.get('parentId')}')")
    
        # 9. Query all blocks from backend
    
        # 10. For Development Guidelines, check for required block types
        dev_blocks = _get_blocks_for_page(final_state_backend, dev_guidelines_id)
    
        if not _has_heading_block(dev_blocks):
            errors.append("[X] Development Guidelines has no heading blocks")
        else:
            checks_passed.append("[C] Development Guidelines has heading blocks")
        if not _has_block_type(dev_blocks, "paragraph"):
            errors.append("[X] Development Guidelines has no paragraph blocks")
        else:
            checks_passed.append("[C] Development Guidelines has paragraph blocks")
        if not _has_block_type(dev_blocks, "code"):
            errors.append("[X] Development Guidelines has no code blocks")
        else:
            checks_passed.append("[C] Development Guidelines has code blocks")
        if not _has_block_type(dev_blocks, "bulletedList"):
            errors.append("[X] Development Guidelines has no bulletedList blocks")
        else:
            checks_passed.append("[C] Development Guidelines has bulletedList blocks")
    
        # 11. For Code Review Process, check same 4 block types
        cr_blocks = _get_blocks_for_page(final_state_backend, code_review_id)
    
        if not _has_heading_block(cr_blocks):
            errors.append("[X] Code Review Process has no heading blocks")
        else:
            checks_passed.append("[C] Code Review Process has heading blocks")
        if not _has_block_type(cr_blocks, "paragraph"):
            errors.append("[X] Code Review Process has no paragraph blocks")
        else:
            checks_passed.append("[C] Code Review Process has paragraph blocks")
        if not _has_block_type(cr_blocks, "code"):
            errors.append("[X] Code Review Process has no code blocks")
        else:
            checks_passed.append("[C] Code Review Process has code blocks")
        if not _has_block_type(cr_blocks, "bulletedList"):
            errors.append("[X] Code Review Process has no bulletedList blocks")
        else:
            checks_passed.append("[C] Code Review Process has bulletedList blocks")
    
        # 12. Check hub page has at least 1 numberedList block (table of contents)
        hub_blocks = _get_blocks_for_page(final_state_backend, eng_hub_id)
        if not _has_block_type(hub_blocks, "numberedList"):
            errors.append("[X] Engineering Docs Hub has no numberedList blocks (table of contents)")
        else:
            checks_passed.append("[C] Engineering Docs Hub has numberedList blocks (table of contents)")
    
        # 13. All checks passed
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_company_culture_creation(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate Company Culture task completion.
    
    Verification:
    - Main page 'Company Culture & Values' exists with heart icon
    - 3 subpages with specified titles and icons:
      - 'Mission & Vision' with target icon
      - 'Team Values' with handshake icon
      - 'Recognition System' with trophy icon
    - Mission & Vision contains headings, quote blocks, and todo blocks
    - Team Values contains headings and paragraphs
    - Recognition contains headings and numberedList blocks
    - 'Old Project Notes' page is archived
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    # 1. Query all pages from backend
    # 2. Find "Company Culture & Values" page
    try:
        culture_page = _find_page_by_title(final_state_backend, "Company Culture")
        if not culture_page:
            errors.append("[X] Company Culture & Values page not found")
        else:
            checks_passed.append("[C] Company Culture & Values page found")
    
        culture_page_id = culture_page.get("_id")
    
        # 3. Check main page has heart icon
        icon = culture_page.get("icon")
        if not _is_heart_icon(icon):
            errors.append(f"[X] Company Culture & Values does not have a heart icon (found: '{icon}')")
        else:
            checks_passed.append(f"[C] Company Culture & Values has a heart icon (found: '{icon}')")
    
        # 4. Find "Mission & Vision" page
        mission_page = _find_page_by_title(final_state_backend, "Mission")
        if not mission_page:
            mission_page = _find_page_by_title(final_state_backend, "Vision")
        if not mission_page:
            errors.append("[X] Mission & Vision page not found")
        else:
            checks_passed.append("[C] Mission & Vision page found")
    
        mission_page_id = mission_page.get("_id")
    
        # 5. Check Mission & Vision has target icon and correct parent
        mission_icon = mission_page.get("icon")
        if not _is_target_icon(mission_icon):
            errors.append(f"[X] Mission & Vision does not have a target icon (found: '{mission_icon}')")
        else:
            checks_passed.append(f"[C] Mission & Vision has a target icon (found: '{mission_icon}')")
    
        if mission_page.get("parentId") != culture_page_id:
            errors.append(f"[X] Mission & Vision is not under Company Culture & Values (parentId: '{mission_page.get('parentId')}')")
        else:
            checks_passed.append(f"[C] Mission & Vision is under Company Culture & Values (parentId: '{mission_page.get('parentId')}')")
    
        # 6. Find "Team Values" page
        team_values_page = _find_page_by_title(final_state_backend, "Team Values")
        if not team_values_page:
            errors.append("[X] Team Values page not found")
        else:
            checks_passed.append("[C] Team Values page found")
    
        team_values_page_id = team_values_page.get("_id")
    
        # 7. Check Team Values has handshake icon and correct parent
        team_values_icon = team_values_page.get("icon")
        if not _is_handshake_icon(team_values_icon):
            errors.append(f"[X] Team Values does not have a handshake icon (found: '{team_values_icon}')")
        else:
            checks_passed.append(f"[C] Team Values has a handshake icon (found: '{team_values_icon}')")
    
        if team_values_page.get("parentId") != culture_page_id:
            errors.append(f"[X] Team Values is not under Company Culture & Values (parentId: '{team_values_page.get('parentId')}')")
        else:
            checks_passed.append(f"[C] Team Values is under Company Culture & Values (parentId: '{team_values_page.get('parentId')}')")
    
        # 8. Find "Recognition System" page
        recognition_page = _find_page_by_title(final_state_backend, "Recognition")
        if not recognition_page:
            errors.append("[X] Recognition System page not found")
        else:
            checks_passed.append("[C] Recognition System page found")
    
        recognition_page_id = recognition_page.get("_id")
    
        # 9. Check Recognition System has trophy icon and correct parent
        recognition_icon = recognition_page.get("icon")
        if not _is_trophy_icon(recognition_icon):
            errors.append(f"[X] Recognition System does not have a trophy icon (found: '{recognition_icon}')")
        else:
            checks_passed.append(f"[C] Recognition System has a trophy icon (found: '{recognition_icon}')")
    
        if recognition_page.get("parentId") != culture_page_id:
            errors.append(f"[X] Recognition System is not under Company Culture & Values (parentId: '{recognition_page.get('parentId')}')")
        else:
            checks_passed.append(f"[C] Recognition System is under Company Culture & Values (parentId: '{recognition_page.get('parentId')}')")
    
        # 10. Query all blocks from backend
    
        # 11. Check Mission & Vision blocks: heading, quote, todo
        mission_blocks = _get_blocks_for_page(final_state_backend, mission_page_id)
    
        if not _has_heading_block(mission_blocks):
            errors.append("[X] Mission & Vision has no heading blocks")
        else:
            checks_passed.append("[C] Mission & Vision has heading blocks")
        if not _has_block_type(mission_blocks, "quote"):
            errors.append("[X] Mission & Vision has no quote blocks")
        else:
            checks_passed.append("[C] Mission & Vision has quote blocks")
        if not _has_block_type(mission_blocks, "todo"):
            errors.append("[X] Mission & Vision has no todo blocks")
        else:
            checks_passed.append("[C] Mission & Vision has todo blocks")
    
        # 12. Check Team Values blocks: heading, paragraph
        team_values_blocks = _get_blocks_for_page(final_state_backend, team_values_page_id)
    
        if not _has_heading_block(team_values_blocks):
            errors.append("[X] Team Values has no heading blocks")
        else:
            checks_passed.append("[C] Team Values has heading blocks")
        if not _has_block_type(team_values_blocks, "paragraph"):
            errors.append("[X] Team Values has no paragraph blocks")
        else:
            checks_passed.append("[C] Team Values has paragraph blocks")
    
        # 13. Check Recognition blocks: heading, numberedList
        recognition_blocks = _get_blocks_for_page(final_state_backend, recognition_page_id)
    
        if not _has_heading_block(recognition_blocks):
            errors.append("[X] Recognition System has no heading blocks")
        else:
            checks_passed.append("[C] Recognition System has heading blocks")
        if not _has_block_type(recognition_blocks, "numberedList"):
            errors.append("[X] Recognition System has no numberedList blocks")
        else:
            checks_passed.append("[C] Recognition System has numberedList blocks")
    
        # 14. Find "Old Project Notes" page and verify isArchived == true
        old_project_notes = _find_page_by_title(final_state_backend, "Old Project Notes")
        if not old_project_notes:
            errors.append("[X] Old Project Notes page not found")
        else:
            checks_passed.append("[C] Old Project Notes page found")
    
        if not old_project_notes.get("isArchived"):
            errors.append("[X] Old Project Notes is not archived")
        else:
            checks_passed.append("[C] Old Project Notes is archived")
    
        # 15. All checks passed
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_project_templates_hub_creation(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate Project Templates Hub task completion.
    
    Verification:
    - New 'Project Templates Hub' page exists with folder icon and is marked as favorite
    - 'Project Kickoff Template' page exists with rocket icon as child of hub
    - 'Weekly Standup Template' moved under hub
    - Hub contains exactly 2 child pages
    - Kickoff template has updated content sections
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    # 1. Query all pages from backend
    # 2. Find "Project Templates Hub" page
    try:
        hub = _find_page_by_title(final_state_backend, "Project Templates Hub")
        if not hub:
            errors.append("[X] Project Templates Hub page not found")
        else:
            checks_passed.append("[C] Project Templates Hub page found")
    
        hub_id = hub.get("_id")
    
        # 3. Check hub has folder icon
        icon = hub.get("icon")
        if not _is_folder_icon(icon):
            errors.append(f"[X] Project Templates Hub does not have a folder icon (found: '{icon}')")
        else:
            checks_passed.append(f"[C] Project Templates Hub has a folder icon (found: '{icon}')")
    
        # 4. Check hub isFavorite == true
        if not hub.get("isFavorite"):
            errors.append("[X] Project Templates Hub is not marked as favorite")
        else:
            checks_passed.append("[C] Project Templates Hub is marked as favorite")
    
        # 5. Find "Project Kickoff Template" page under the hub
        kickoff = _find_page_by_title_pattern_and_parent(final_state_backend, "Project Kickoff", hub_id)
        if not kickoff:
            # Fallback: check if any kickoff exists but with wrong parent
            any_kickoff = _find_page_by_title(final_state_backend, "Project Kickoff")
            if any_kickoff:
                errors.append(f"[X] Project Kickoff Template exists but is not under Project Templates Hub (parentId: '{any_kickoff.get('parentId')}')")
            else:
                checks_passed.append(f"[C] Project Kickoff Template exists but is under Project Templates Hub (parentId: '{any_kickoff.get('parentId')}')")
            errors.append("[X] Project Kickoff Template page not found")
        else:
            checks_passed.append("[C] Project Kickoff Template page found")

        kickoff_id = kickoff.get("_id")

        # 6. Check kickoff has rocket icon
        kickoff_icon = kickoff.get("icon")
        if not _is_rocket_icon(kickoff_icon):
            errors.append(f"[X] Project Kickoff Template does not have a rocket icon (found: '{kickoff_icon}')")
        else:
            checks_passed.append(f"[C] Project Kickoff Template has a rocket icon (found: '{kickoff_icon}')")

        # 7. Find "Weekly Standup Template" page under the hub
        standup = _find_page_by_title_pattern_and_parent(final_state_backend, "Weekly Standup Template", hub_id)
        if not standup:
            # Fallback: check if any standup exists but with wrong parent
            any_standup = _find_page_by_title(final_state_backend, "Weekly Standup Template")
            if any_standup:
                errors.append(f"[X] Weekly Standup Template exists but is not under Project Templates Hub (parentId: '{any_standup.get('parentId')}')")
            else:
                checks_passed.append(f"[C] Weekly Standup Template exists but is under Project Templates Hub (parentId: '{any_standup.get('parentId')}')")
            errors.append("[X] Weekly Standup Template page not found")
        else:
            checks_passed.append("[C] Weekly Standup Template page found")
    
        # 10. Count child pages under hub == exactly 2
        child_pages = _get_child_pages(final_state_backend, hub_id)
        if len(child_pages) != 2:
            errors.append(f"[X] Project Templates Hub has {len(child_pages)} child pages, expected exactly 2")
        else:
            checks_passed.append(f"[C] Project Templates Hub has {len(child_pages)} child pages, expected exactly 2")
    
        # 11. Query all blocks from backend
    
        # 12. Check kickoff page has heading blocks containing required sections
        kickoff_blocks = _get_blocks_for_page(final_state_backend, kickoff_id)
    
        # Get heading content for kickoff
        heading_contents = [
            b.get("content", "").lower() 
            for b in kickoff_blocks 
            if b.get("type") in {"heading1", "heading2", "heading3"}
        ]
    
        # Check for "overview" or "project overview"
        has_overview = any("overview" in c or "project" in c for c in heading_contents)
        if not has_overview:
            errors.append("[X] Project Kickoff Template missing 'overview' or 'project overview' section")
        else:
            checks_passed.append("[C] Project Kickoff Template has 'overview' or 'project overview' section")
    
        # Check for "assignment" or "team"
        has_assignments = any("assignment" in c or "team" in c for c in heading_contents)
        if not has_assignments:
            errors.append("[X] Project Kickoff Template missing 'team assignments' section")
        else:
            checks_passed.append("[C] Project Kickoff Template has 'team assignments' section")
    
        # Check for "metric" or "success"
        has_metrics = any("metric" in c or "success" in c for c in heading_contents)
        if not has_metrics:
            errors.append("[X] Project Kickoff Template missing 'success metrics' section")
        else:
            checks_passed.append("[C] Project Kickoff Template has 'success metrics' section")
    
        # 13. All checks passed
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_company_handbook_swap_with_bookmark(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate Company Handbook swap Values/Benefits with bookmark addition.
    
    Verification:
    - Our Values and Benefits sections are completely swapped
    - New bookmark block after Benefits numbered list
    - Quote block between Work Policies and Remote Work
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    # 1. Query all pages from backend
    # 2. Find 'Company Handbook' page
    try:
        handbook = _find_page_by_title(final_state_backend, "Company Handbook")
        if not handbook:
            errors.append("[X] Company Handbook page not found")
        else:
            checks_passed.append("[C] Company Handbook page found")
    
        handbook_id = handbook.get("_id")
    
        # 3. Query all blocks for the page
        page_blocks = _get_blocks_for_page(final_state_backend, handbook_id)
    
        if not page_blocks:
            errors.append("[X] Company Handbook page has no blocks")
        else:
            checks_passed.append("[C] Company Handbook page has blocks")
    
        # Sort blocks by order
        page_blocks_sorted = sorted(page_blocks, key=lambda b: b.get("order", 0))
    
        # 4. Find 'Our Values' heading
        values_heading = None
        for block in page_blocks_sorted:
            if block.get("type") in {"heading1", "heading2"}:
                content = block.get("content", "").lower()
                if "our values" in content or "values" in content:
                    values_heading = block
                    break
    
        if not values_heading:
            errors.append("[X] Our Values heading not found")
        else:
            checks_passed.append("[C] Our Values heading found")
    
        values_order = values_heading.get("order", 0)
    
        # 5. Find 'Benefits' heading
        benefits_heading = None
        for block in page_blocks_sorted:
            if block.get("type") in {"heading1", "heading2"}:
                content = block.get("content", "").lower()
                if "benefits" in content:
                    benefits_heading = block
                    break
    
        if not benefits_heading:
            errors.append("[X] Benefits heading not found")
        else:
            checks_passed.append("[C] Benefits heading found")
    
        benefits_order = benefits_heading.get("order", 0)
    
        # 6. Verify Benefits now comes before Our Values (swapped)
        if benefits_order >= values_order:
            errors.append(f"[X] Benefits should appear before Our Values after swap (Benefits: {benefits_order}, Values: {values_order})")
        else:
            checks_passed.append(f"[C] Benefits should appear before Our Values after swap (Benefits: {benefits_order}, Values: {values_order})")
    
        # 7. Find bookmark block
        bookmark_found = False
        for block in page_blocks_sorted:
            if block.get("type") == "bookmark":
                order = block.get("order", 0)
                # Should be after benefits heading
                if order > benefits_order:
                    bookmark_found = True
                    break
    
        if not bookmark_found:
            errors.append("[X] Bookmark block not found after Benefits section")
        else:
            checks_passed.append("[C] Bookmark block found after Benefits section")
    
        # 8. Find quote block
        quote_found = False
        for block in page_blocks_sorted:
            if block.get("type") == "quote":
                content = block.get("content", "").lower()
                if "flexibility" in content or "autonomy" in content or "innovation" in content:
                    quote_found = True
                    break
    
        if not quote_found:
            errors.append("[X] Quote block about flexibility and autonomy not found")
        else:
            checks_passed.append("[C] Quote block about flexibility and autonomy found")
    
        # 9. All checks passed
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_quarterly_goals_dashboard_creation(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate Quarterly Goals Dashboard new page creation.
    
    Verification:
    - New page 'Quarterly Goals Dashboard' created as sibling to Project Roadmap
    - heading1 with dashboard title
    - heading2 '2024 Roadmap Summary'
    - Sections for each quarter page found with status callouts
    - Toggle blocks with completed/remaining tasks
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    # 1. Query all pages from backend
    # 2. Find 'Quarterly Goals Dashboard' page
    try:
        dashboard = _find_page_by_title(final_state_backend, "Quarterly Goals Dashboard")
        if not dashboard:
            errors.append("[X] Quarterly Goals Dashboard page not found")
        else:
            checks_passed.append("[C] Quarterly Goals Dashboard page found")
    
        dashboard_id = dashboard.get("_id")
    
        # 3. Query all blocks for the page
        page_blocks = _get_blocks_for_page(final_state_backend, dashboard_id)
    
        if not page_blocks:
            errors.append("[X] Quarterly Goals Dashboard page has no blocks")
        else:
            checks_passed.append("[C] Quarterly Goals Dashboard page has blocks")
    
        # 4. Check for heading1
        has_heading1 = any(b.get("type") == "heading1" for b in page_blocks)
        if not has_heading1:
            errors.append("[X] Quarterly Goals Dashboard missing heading1")
        else:
            checks_passed.append("[C] Quarterly Goals Dashboard has heading1")
    
        # 5. Check for Roadmap Summary heading2
        has_summary = any(
            b.get("type") == "heading2" and "roadmap" in b.get("content", "").lower() and "summary" in b.get("content", "").lower()
            for b in page_blocks
        )
        if not has_summary:
            errors.append("[X] 2024 Roadmap Summary heading2 not found")
        else:
            checks_passed.append("[C] 2024 Roadmap Summary heading2 found")
    
        # 6. Check for toggle blocks
        toggle_blocks = [b for b in page_blocks if b.get("type") == "toggle"]
        if not toggle_blocks:
            errors.append("[X] No toggle blocks found for quarter details")
        else:
            checks_passed.append("[C] toggle blocks found for quarter details")
    
        # 7. All checks passed
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_workspace_analytics_dashboard_creation(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate Workspace Analytics Dashboard new page creation.
    
    Verification:
    - New page 'Workspace Analytics Dashboard' created at root level
    - heading1 with dashboard title
    - heading2 'Page Comparison Matrix'
    - Multiple callouts showing statistics
    - heading2 'Key Insights' with bulleted list
    - Bookmark block
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    # 1. Query all pages from backend
    # 2. Find 'Workspace Analytics Dashboard' page
    try:
        dashboard = _find_page_by_title(final_state_backend, "Workspace Analytics Dashboard")
        if not dashboard:
            errors.append("[X] Workspace Analytics Dashboard page not found")
        else:
            checks_passed.append("[C] Workspace Analytics Dashboard page found")
    
        dashboard_id = dashboard.get("_id")
    
        # 3. Query all blocks for the page
        page_blocks = _get_blocks_for_page(final_state_backend, dashboard_id)
    
        if not page_blocks:
            errors.append("[X] Workspace Analytics Dashboard page has no blocks")
        else:
            checks_passed.append("[C] Workspace Analytics Dashboard page has blocks")
    
        # 4. Check for heading1
        has_heading1 = any(b.get("type") == "heading1" for b in page_blocks)
        if not has_heading1:
            errors.append("[X] Workspace Analytics Dashboard missing heading1")
        else:
            checks_passed.append("[C] Workspace Analytics Dashboard has heading1")
    
        # 5. Check for Page Comparison Matrix heading2
        has_matrix = any(
            b.get("type") == "heading2" and "comparison" in b.get("content", "").lower() and "matrix" in b.get("content", "").lower()
            for b in page_blocks
        )
        if not has_matrix:
            errors.append("[X] Page Comparison Matrix heading2 not found")
        else:
            checks_passed.append("[C] Page Comparison Matrix heading2 found")
    
        # 6. Check for callout blocks (should have multiple for matrix)
        callouts = [b for b in page_blocks if b.get("type") == "callout"]
        if len(callouts) < 3:
            errors.append(f"[X] Expected at least 3 callout blocks for matrix (found: {len(callouts)})")
        else:
            checks_passed.append(f"[C] Expected at least 3 callout blocks for matrix (found: {len(callouts)})")
    
        # 7. Check for Key Insights heading2
        has_insights = any(
            b.get("type") == "heading2" and "key insights" in b.get("content", "").lower()
            for b in page_blocks
        )
        if not has_insights:
            errors.append("[X] Key Insights heading2 not found")
        else:
            checks_passed.append("[C] Key Insights heading2 found")
    
        # 8. All checks passed
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_sprint_planning_hub_creation(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate Sprint Planning Hub new page creation.
    
    Verification:
    - New page 'Sprint Planning Hub' created
    - heading1 with hub title
    - Green callout with Agile Sprint Management Center
    - Multiple heading2 and heading3 sections
    - Numbered list with 5 sprint goals
    - Todo blocks for velocity tracking
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    # 1. Query all pages from backend
    # 2. Find 'Sprint Planning Hub' page
    try:
        hub = _find_page_by_title(final_state_backend, "Sprint Planning Hub")
        if not hub:
            errors.append("[X] Sprint Planning Hub page not found")
        else:
            checks_passed.append("[C] Sprint Planning Hub page found")
    
        hub_id = hub.get("_id")
    
        # 3. Query all blocks for the page
        page_blocks = _get_blocks_for_page(final_state_backend, hub_id)
    
        if not page_blocks:
            errors.append("[X] Sprint Planning Hub page has no blocks")
        else:
            checks_passed.append("[C] Sprint Planning Hub page has blocks")
    
        # 4. Check for heading1
        has_heading1 = any(b.get("type") == "heading1" for b in page_blocks)
        if not has_heading1:
            errors.append("[X] Sprint Planning Hub missing heading1")
        else:
            checks_passed.append("[C] Sprint Planning Hub has heading1")
    
        # 5. Check for green callout
        has_green_callout = any(
            b.get("type") == "callout" and "green" in b.get("properties", {}).get("backgroundColor", "").lower()
            for b in page_blocks
        )
        if not has_green_callout:
            errors.append("[X] Green callout with Agile Sprint Management Center not found")
        else:
            checks_passed.append("[C] Green callout with Agile Sprint Management Center found")
    
        # 6. Check for numbered list (sprint goals)
        numbered_lists = [b for b in page_blocks if b.get("type") == "numberedList"]
        if len(numbered_lists) < 5:
            errors.append(f"[X] Expected at least 5 numbered list items for sprint goals (found: {len(numbered_lists)})")
        else:
            checks_passed.append(f"[C] Expected at least 5 numbered list items for sprint goals (found: {len(numbered_lists)})")
    
        # 7. Check for todo blocks (velocity tracking)
        todos = [b for b in page_blocks if b.get("type") == "todo"]
        if len(todos) < 3:
            errors.append(f"[X] Expected at least 3 todo blocks for velocity tracking (found: {len(todos)})")
        else:
            checks_passed.append(f"[C] Expected at least 3 todo blocks for velocity tracking (found: {len(todos)})")
    
        # 8. All checks passed
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_weekly_standup_date_section(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate Weekly Standup Date section task.
    
    Verification:
    - Date section with bold date header after 'This Week' heading
    - Exactly 3 unchecked todos with specific tasks
    - Blue callout at end with sprint velocity
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    # 1. Query all pages from backend
    # 2. Find 'Weekly Standup Template' page
    try:
        standup = _find_page_by_title(final_state_backend, "Weekly Standup Template")
        if not standup:
            errors.append("[X] Weekly Standup Template page not found")
        else:
            checks_passed.append("[C] Weekly Standup Template page found")
    
        standup_id = standup.get("_id")
    
        # 3. Query all blocks for the page
        page_blocks = _get_blocks_for_page(final_state_backend, standup_id)
    
        if not page_blocks:
            errors.append("[X] Weekly Standup Template page has no blocks")
        else:
            checks_passed.append("[C] Weekly Standup Template page has blocks")
    
        # Sort blocks by order
        page_blocks_sorted = sorted(page_blocks, key=lambda b: b.get("order", 0))
    
        # 4. Find 'In Progress' or 'This Week' heading
        in_progress_heading = None
        for block in page_blocks_sorted:
            if block.get("type") in {"heading1", "heading2", "heading3"}:
                content = block.get("content", "").lower()
                if "in progress" in content or "this week" in content:
                    in_progress_heading = block
                    break
    
        if not in_progress_heading:
            errors.append("[X] In Progress or This Week heading not found")
        else:
            checks_passed.append("[C] In Progress or This Week heading found")
    
        in_progress_order = in_progress_heading.get("order", 0)
    
        # 5. Check for todos after the heading
        todos_after = [
            b for b in page_blocks_sorted
            if b.get("type") == "todo" and b.get("order", 0) > in_progress_order
        ]
    
        if len(todos_after) < 3:
            errors.append(f"[X] Expected at least 3 todo blocks in date section (found: {len(todos_after)})")
        else:
            checks_passed.append(f"[C] Expected at least 3 todo blocks in date section (found: {len(todos_after)})")
    
        # 6. Find blue callout at end
        callout_found = False
        for block in reversed(page_blocks_sorted[-15:]):
            if block.get("type") == "callout":
                bg_color = block.get("properties", {}).get("backgroundColor", "").lower()
                content = block.get("content", "").lower()
            
                if "blue" in bg_color and ("sprint velocity" in content or "story points" in content):
                    callout_found = True
                    break
    
        if not callout_found:
            errors.append("[X] Blue callout with sprint velocity not found at end")
        else:
            checks_passed.append("[C] Blue callout with sprint velocity found at end")
    
        # 7. All checks passed
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_api_documentation_index_creation(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate API Documentation Index new page creation.
    
    Verification:
    - New page 'API Documentation Index' created as child of API Documentation
    - heading1 with index title
    - Yellow callout with quick access message
    - heading2 'Table of Contents'
    - Numbered list with TOC items
    - heading2 'Endpoint Summary'
    - Gray callout with documentation metrics
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    # 1. Query all pages from backend
    # 2. Find 'API Documentation Index' page
    try:
        index_page = _find_page_by_title(final_state_backend, "API Documentation Index")
        if not index_page:
            errors.append("[X] API Documentation Index page not found")
        else:
            checks_passed.append("[C] API Documentation Index page found")
    
        index_page_id = index_page.get("_id")
    
        # 3. Find API Documentation parent page
        api_doc = _find_page_by_title(final_state_backend, "API Documentation")
        if api_doc:
            # Verify parent relationship
            if index_page.get("parentId") != api_doc.get("_id"):
                errors.append(f"[X] API Documentation Index should be child of API Documentation (parentId: '{index_page.get('parentId')}')")
            else:
                checks_passed.append(f"[C] API Documentation Index should be child of API Documentation (parentId: '{index_page.get('parentId')}')")
    
        # 4. Query all blocks for the page
        page_blocks = _get_blocks_for_page(final_state_backend, index_page_id)
    
        if not page_blocks:
            errors.append("[X] API Documentation Index page has no blocks")
        else:
            checks_passed.append("[C] API Documentation Index page has blocks")
    
        # 5. Check for yellow callout
        has_yellow_callout = any(
            b.get("type") == "callout" and "yellow" in b.get("properties", {}).get("backgroundColor", "").lower()
            for b in page_blocks
        )
        if not has_yellow_callout:
            errors.append("[X] Yellow callout with quick access message not found")
        else:
            checks_passed.append("[C] Yellow callout with quick access message found")
    
        # 6. Check for Table of Contents heading2
        has_toc = any(
            b.get("type") == "heading2" and "table of contents" in b.get("content", "").lower()
            for b in page_blocks
        )
        if not has_toc:
            errors.append("[X] Table of Contents heading2 not found")
        else:
            checks_passed.append("[C] Table of Contents heading2 found")
    
        # 7. Check for gray callout with metrics
        has_gray_callout = any(
            b.get("type") == "callout" and "gray" in b.get("properties", {}).get("backgroundColor", "").lower()
            for b in page_blocks
        )
        if not has_gray_callout:
            errors.append("[X] Gray callout with documentation metrics not found")
        else:
            checks_passed.append("[C] Gray callout with documentation metrics found")
    
        # 8. All checks passed
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_q1_onboarding_tracker_creation(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate Q1 2024 Onboarding Tracker new page creation.
    
    Verification:
    - New page 'Q1 2024 Onboarding Tracker' created as child of Onboarding Guide
    - heading1 with tracker title
    - heading2 'January Cohort'
    - Yellow callout with welcome message
    - Two heading3 sections: 'Week 1 Tasks' and 'Week 2-4 Tasks'
    - 8 total todos (4 per week section)
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    # 1. Query all pages from backend
    # 2. Find 'Q1 2024 Onboarding Tracker' page
    try:
        tracker = _find_page_by_title(final_state_backend, "Q1 2024 Onboarding Tracker")
        if not tracker:
            errors.append("[X] Q1 2024 Onboarding Tracker page not found")
        else:
            checks_passed.append("[C] Q1 2024 Onboarding Tracker page found")
    
        tracker_id = tracker.get("_id")
    
        # 3. Find Onboarding Guide parent page
        onboarding_guide = _find_page_by_title(final_state_backend, "Onboarding Guide")
        if onboarding_guide:
            # Verify parent relationship
            if tracker.get("parentId") != onboarding_guide.get("_id"):
                errors.append(f"[X] Q1 2024 Onboarding Tracker should be child of Onboarding Guide (parentId: '{tracker.get('parentId')}')")
            else:
                checks_passed.append(f"[C] Q1 2024 Onboarding Tracker should be child of Onboarding Guide (parentId: '{tracker.get('parentId')}')")
    
        # 4. Query all blocks for the page
        page_blocks = _get_blocks_for_page(final_state_backend, tracker_id)
    
        if not page_blocks:
            errors.append("[X] Q1 2024 Onboarding Tracker page has no blocks")
        else:
            checks_passed.append("[C] Q1 2024 Onboarding Tracker page has blocks")
    
        # 5. Check for yellow callout
        has_yellow_callout = any(
            b.get("type") == "callout" and "yellow" in b.get("properties", {}).get("backgroundColor", "").lower()
            for b in page_blocks
        )
        if not has_yellow_callout:
            errors.append("[X] Yellow callout with welcome message not found")
        else:
            checks_passed.append("[C] Yellow callout with welcome message found")
    
        # 6. Check for Week 1 Tasks heading3
        has_week1 = any(
            b.get("type") == "heading3" and "week 1" in b.get("content", "").lower()
            for b in page_blocks
        )
        if not has_week1:
            errors.append("[X] Week 1 Tasks heading3 not found")
        else:
            checks_passed.append("[C] Week 1 Tasks heading3 found")
    
        # 7. Check for Week 2-4 Tasks heading3
        has_week24 = any(
            b.get("type") == "heading3" and ("week 2" in b.get("content", "").lower() or "week 2-4" in b.get("content", "").lower())
            for b in page_blocks
        )
        if not has_week24:
            errors.append("[X] Week 2-4 Tasks heading3 not found")
        else:
            checks_passed.append("[C] Week 2-4 Tasks heading3 found")
    
        # 8. Check for todos
        todos = [b for b in page_blocks if b.get("type") == "todo"]
        if len(todos) < 8:
            errors.append(f"[X] Expected at least 8 todo blocks (found: {len(todos)})")
        else:
            checks_passed.append(f"[C] Expected at least 8 todo blocks (found: {len(todos)})")
    
        # 9. All checks passed
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_team_task_overview_creation(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate Team Task Overview new page creation.
    
    Verification:
    - New page 'Team Task Overview' created under Team Directory
    - heading1 with overview title
    - heading2 'Task Analysis by Type'
    - heading2 'Priority Distribution'
    - Orange callout with recommendation
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    # 1. Query all pages from backend
    # 2. Find 'Team Task Overview' page
    try:
        overview = _find_page_by_title(final_state_backend, "Team Task Overview")
        if not overview:
            errors.append("[X] Team Task Overview page not found")
        else:
            checks_passed.append("[C] Team Task Overview page found")
    
        overview_id = overview.get("_id")
    
        # 3. Find Team Directory parent page
        team_directory = _find_page_by_title(final_state_backend, "Team Directory")
        if team_directory:
            # Verify parent relationship
            if overview.get("parentId") != team_directory.get("_id"):
                errors.append(f"[X] Team Task Overview should be child of Team Directory (parentId: '{overview.get('parentId')}')")
            else:
                checks_passed.append(f"[C] Team Task Overview should be child of Team Directory (parentId: '{overview.get('parentId')}')")
    
        # 4. Query all blocks for the page
        page_blocks = _get_blocks_for_page(final_state_backend, overview_id)
    
        if not page_blocks:
            errors.append("[X] Team Task Overview page has no blocks")
        else:
            checks_passed.append("[C] Team Task Overview page has blocks")
    
        # 5. Check for Task Analysis heading2
        has_analysis = any(
            b.get("type") == "heading2" and "task analysis" in b.get("content", "").lower()
            for b in page_blocks
        )
        if not has_analysis:
            errors.append("[X] Task Analysis by Type heading2 not found")
        else:
            checks_passed.append("[C] Task Analysis by Type heading2 found")
    
        # 6. Check for Priority Distribution heading2
        has_priority = any(
            b.get("type") == "heading2" and "priority distribution" in b.get("content", "").lower()
            for b in page_blocks
        )
        if not has_priority:
            errors.append("[X] Priority Distribution heading2 not found")
        else:
            checks_passed.append("[C] Priority Distribution heading2 found")
    
        # 7. Check for orange callout
        has_orange_callout = any(
            b.get("type") == "callout" and "orange" in b.get("properties", {}).get("backgroundColor", "").lower()
            for b in page_blocks
        )
        if not has_orange_callout:
            errors.append("[X] Orange callout with recommendation not found")
        else:
            checks_passed.append("[C] Orange callout with recommendation found")
    
        # 8. All checks passed
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_design_system_audit_creation(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate Design System Audit new page creation.
    
    Verification:
    - New page 'Design System Audit' created as child of Design System
    - heading1 with audit title
    - heading2 'Visual Asset Inventory'
    - heading2 'Component Documentation Status'
    - Purple callout with audit summary
    - Todo blocks for documentation status
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    # 1. Query all pages from backend
    # 2. Find 'Design System Audit' page
    try:
        audit = _find_page_by_title(final_state_backend, "Design System Audit")
        if not audit:
            errors.append("[X] Design System Audit page not found")
        else:
            checks_passed.append("[C] Design System Audit page found")
    
        audit_id = audit.get("_id")
    
        # 3. Find Design System parent page
        design_system = _find_page_by_title(final_state_backend, "Design System")
        if design_system:
            # Verify parent relationship
            if audit.get("parentId") != design_system.get("_id"):
                errors.append(f"[X] Design System Audit should be child of Design System (parentId: '{audit.get('parentId')}')")
            else:
                checks_passed.append(f"[C] Design System Audit should be child of Design System (parentId: '{audit.get('parentId')}')")
    
        # 4. Query all blocks for the page
        page_blocks = _get_blocks_for_page(final_state_backend, audit_id)
    
        if not page_blocks:
            errors.append("[X] Design System Audit page has no blocks")
        else:
            checks_passed.append("[C] Design System Audit page has blocks")
    
        # 5. Check for Visual Asset Inventory heading2
        has_inventory = any(
            b.get("type") == "heading2" and "visual asset" in b.get("content", "").lower() and "inventory" in b.get("content", "").lower()
            for b in page_blocks
        )
        if not has_inventory:
            errors.append("[X] Visual Asset Inventory heading2 not found")
        else:
            checks_passed.append("[C] Visual Asset Inventory heading2 found")
    
        # 6. Check for Component Documentation Status heading2
        has_status = any(
            b.get("type") == "heading2" and "component" in b.get("content", "").lower() and "documentation" in b.get("content", "").lower()
            for b in page_blocks
        )
        if not has_status:
            errors.append("[X] Component Documentation Status heading2 not found")
        else:
            checks_passed.append("[C] Component Documentation Status heading2 found")
    
        # 7. Check for purple callout
        has_purple_callout = any(
            b.get("type") == "callout" and "purple" in b.get("properties", {}).get("backgroundColor", "").lower()
            for b in page_blocks
        )
        if not has_purple_callout:
            errors.append("[X] Purple callout with audit summary not found")
        else:
            checks_passed.append("[C] Purple callout with audit summary found")
    
        # 8. All checks passed
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_sprint_planning_retrospective_variant(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate Sprint Planning Retrospective variant task.
    
    Verification:
    - Retrospective section after Action Items with divider
    - heading2 'Sprint Retrospective'
    - heading3 'Achievements' with completion stats paragraph
    - heading3 'Goal Analysis' with goal todos
    - Green callout with conditional status message
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    # 1. Find 'Sprint Planning - Jan 15' page
    try:
        sprint_page = _find_page_with_all_title_patterns(final_state_backend, ["sprint planning", "jan"])
        if not sprint_page:
            errors.append("[X] Sprint Planning - Jan 15 page not found")
        else:
            checks_passed.append("[C] Sprint Planning - Jan 15 page found")

        sprint_page_id = sprint_page.get("_id")

        # 2. Query all blocks for the page
        page_blocks = _get_blocks_for_page(final_state_backend, sprint_page_id)
    
        if not page_blocks:
            errors.append("[X] Sprint Planning page has no blocks")
        else:
            checks_passed.append("[C] Sprint Planning page has blocks")
    
        # Sort blocks by order
        page_blocks_sorted = sorted(page_blocks, key=lambda b: b.get("order", 0))
    
        # 4. Find 'Sprint Retrospective' heading2
        retrospective_heading = None
        for block in page_blocks_sorted:
            if block.get("type") == "heading2":
                content = block.get("content", "").lower()
                if "sprint retrospective" in content or ("sprint" in content and "retrospective" in content):
                    retrospective_heading = block
                    break
    
        if not retrospective_heading:
            errors.append("[X] Sprint Retrospective heading2 not found")
        else:
            checks_passed.append("[C] Sprint Retrospective heading2 found")
    
        retrospective_order = retrospective_heading.get("order", 0)
    
        # 5. Find 'Achievements' heading3
        achievements_found = False
        for block in page_blocks_sorted:
            if block.get("type") == "heading3" and block.get("order", 0) > retrospective_order:
                content = block.get("content", "").lower()
                if "achievements" in content:
                    achievements_found = True
                    break
    
        if not achievements_found:
            errors.append("[X] Achievements heading3 not found")
        else:
            checks_passed.append("[C] Achievements heading3 found")
    
        # 6. Find 'Goal Analysis' heading3
        goal_analysis_found = False
        for block in page_blocks_sorted:
            if block.get("type") == "heading3" and block.get("order", 0) > retrospective_order:
                content = block.get("content", "").lower()
                if "goal" in content and "analysis" in content:
                    goal_analysis_found = True
                    break
    
        if not goal_analysis_found:
            errors.append("[X] Goal Analysis heading3 not found")
        else:
            checks_passed.append("[C] Goal Analysis heading3 found")
    
        # 7. Find green callout with status
        callout_found = False
        for block in page_blocks_sorted:
            if block.get("type") == "callout" and block.get("order", 0) > retrospective_order:
                bg_color = block.get("properties", {}).get("backgroundColor", "").lower()
                content = block.get("content", "").lower()
            
                if "green" in bg_color and ("sprint status" in content or "status:" in content):
                    callout_found = True
                    break
    
        if not callout_found:
            errors.append("[X] Green callout with Sprint Status not found")
        else:
            checks_passed.append("[C] Green callout with Sprint Status found")
    
        # 8. All checks passed
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_engineering_wiki_reorganization_2(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate Engineering Wiki reorganization task.
    
    Verification:
    - Tech Stack and Development Setup sections are swapped
    - New 'Tools & Resources' section between swapped sections
    - heading2 with paragraph and 4 bookmark blocks
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    # 1. Query all pages from backend
    # 2. Find 'Engineering Wiki' page
    try:
        eng_wiki = _find_page_by_title(final_state_backend, "Engineering Wiki")
        if not eng_wiki:
            errors.append("[X] Engineering Wiki page not found")
        else:
            checks_passed.append("[C] Engineering Wiki page found")
    
        eng_wiki_id = eng_wiki.get("_id")
    
        # 3. Query all blocks for the page
        page_blocks = _get_blocks_for_page(final_state_backend, eng_wiki_id)
    
        if not page_blocks:
            errors.append("[X] Engineering Wiki page has no blocks")
        else:
            checks_passed.append("[C] Engineering Wiki page has blocks")
    
        # Sort blocks by order
        page_blocks_sorted = sorted(page_blocks, key=lambda b: b.get("order", 0))
    
        # 4. Find 'Tech Stack' heading
        tech_stack_heading = None
        for block in page_blocks_sorted:
            if block.get("type") in {"heading1", "heading2"}:
                content = block.get("content", "").lower()
                if "tech stack" in content:
                    tech_stack_heading = block
                    break
    
        if not tech_stack_heading:
            errors.append("[X] Tech Stack heading not found")
        else:
            checks_passed.append("[C] Tech Stack heading found")
    
        tech_stack_order = tech_stack_heading.get("order", 0)
    
        # 5. Find 'Development Setup' heading
        dev_setup_heading = None
        for block in page_blocks_sorted:
            if block.get("type") in {"heading1", "heading2"}:
                content = block.get("content", "").lower()
                if "development setup" in content or ("development" in content and "setup" in content):
                    dev_setup_heading = block
                    break
    
        if not dev_setup_heading:
            errors.append("[X] Development Setup heading not found")
        else:
            checks_passed.append("[C] Development Setup heading found")
    
        dev_setup_order = dev_setup_heading.get("order", 0)
    
        # 6. Verify Dev Setup now comes before Tech Stack (swapped)
        if dev_setup_order >= tech_stack_order:
            errors.append(f"[X] Development Setup should appear before Tech Stack after swap (DevSetup: {dev_setup_order}, TechStack: {tech_stack_order})")
        else:
            checks_passed.append(f"[C] Development Setup should appear before Tech Stack after swap (DevSetup: {dev_setup_order}, TechStack: {tech_stack_order})")
    
        # 7. Find 'Tools & Resources' heading2
        tools_heading = None
        for block in page_blocks_sorted:
            if block.get("type") == "heading2":
                content = block.get("content", "").lower()
                if "tools" in content and "resources" in content:
                    tools_heading = block
                    break
    
        if not tools_heading:
            errors.append("[X] Tools & Resources heading2 not found")
        else:
            checks_passed.append("[C] Tools & Resources heading2 found")
    
        tools_order = tools_heading.get("order", 0)
    
        # 8. Verify Tools & Resources is between swapped sections
        if not (dev_setup_order < tools_order < tech_stack_order):
            errors.append(f"[X] Tools & Resources should be between Development Setup and Tech Stack (DevSetup: {dev_setup_order}, Tools: {tools_order}, TechStack: {tech_stack_order})")
        else:
            checks_passed.append(f"[C] Tools & Resources should be between Development Setup and Tech Stack (DevSetup: {dev_setup_order}, Tools: {tools_order}, TechStack: {tech_stack_order})")
    
        # 9. Count bookmark blocks in Tools section
        bookmark_blocks = [
            b for b in page_blocks_sorted
            if b.get("type") == "bookmark" and tools_order < b.get("order", 0) < tech_stack_order
        ]
    
        if len(bookmark_blocks) < 4:
            errors.append(f"[X] Expected at least 4 bookmark blocks in Tools & Resources (found: {len(bookmark_blocks)})")
        else:
            checks_passed.append(f"[C] Expected at least 4 bookmark blocks in Tools & Resources (found: {len(bookmark_blocks)})")
    
        # 10. All checks passed
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_company_handbook_swap_with_home_office(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate Company Handbook swap Values/Benefits with Home Office addition.
    
    Verification:
    - Our Values and Benefits sections are swapped
    - New 'Home Office Setup' heading3 in Work Policies
    - Positioned between Remote Work and Time Off subsections
    - Yellow callout with money bag icon
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    # 1. Query all pages from backend
    # 2. Find 'Company Handbook' page
    try:
        handbook = _find_page_by_title(final_state_backend, "Company Handbook")
        if not handbook:
            errors.append("[X] Company Handbook page not found")
        else:
            checks_passed.append("[C] Company Handbook page found")
    
        handbook_id = handbook.get("_id")
    
        # 3. Query all blocks for the page
        page_blocks = _get_blocks_for_page(final_state_backend, handbook_id)
    
        if not page_blocks:
            errors.append("[X] Company Handbook page has no blocks")
        else:
            checks_passed.append("[C] Company Handbook page has blocks")
    
        # Sort blocks by order
        page_blocks_sorted = sorted(page_blocks, key=lambda b: b.get("order", 0))
    
        # 4. Find 'Our Values' heading
        values_heading = None
        for block in page_blocks_sorted:
            if block.get("type") in {"heading1", "heading2"}:
                content = block.get("content", "").lower()
                if "our values" in content or "values" in content:
                    values_heading = block
                    break
    
        if not values_heading:
            errors.append("[X] Our Values heading not found")
        else:
            checks_passed.append("[C] Our Values heading found")
    
        values_order = values_heading.get("order", 0)
    
        # 5. Find 'Benefits' heading
        benefits_heading = None
        for block in page_blocks_sorted:
            if block.get("type") in {"heading1", "heading2"}:
                content = block.get("content", "").lower()
                if "benefits" in content:
                    benefits_heading = block
                    break
    
        if not benefits_heading:
            errors.append("[X] Benefits heading not found")
        else:
            checks_passed.append("[C] Benefits heading found")
    
        benefits_order = benefits_heading.get("order", 0)
    
        # 6. Verify Benefits now comes before Our Values (swapped)
        if benefits_order >= values_order:
            errors.append(f"[X] Benefits should appear before Our Values after swap (Benefits: {benefits_order}, Values: {values_order})")
        else:
            checks_passed.append(f"[C] Benefits should appear before Our Values after swap (Benefits: {benefits_order}, Values: {values_order})")
    
        # 7. Find 'Home Office Setup' heading3
        home_office_found = False
        for block in page_blocks_sorted:
            if block.get("type") == "heading3":
                content = block.get("content", "").lower()
                if "home office" in content and "setup" in content:
                    home_office_found = True
                    break
    
        if not home_office_found:
            errors.append("[X] Home Office Setup heading3 not found")
        else:
            checks_passed.append("[C] Home Office Setup heading3 found")
    
        # 8. Find yellow callout
        callout_found = False
        for block in page_blocks_sorted:
            if block.get("type") == "callout":
                bg_color = block.get("properties", {}).get("backgroundColor", "").lower()
                content = block.get("content", "").lower()
            
                if "yellow" in bg_color and ("eligible" in content or "equipment" in content or "stipend" in content):
                    callout_found = True
                    break
    
        if not callout_found:
            errors.append("[X] Yellow callout with home office information not found")
        else:
            checks_passed.append("[C] Yellow callout with home office information found")
    
        # 9. All checks passed
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_feature_requests_reorganization_with_calculations(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate Feature Requests reorganization with calculations task.
    
    Verification:
    - Green callout with implementation progress before sections
    - High Priority and Community Suggestions sections are swapped
    - New todo 'Real-time collaborative editing' in relocated High Priority
    - Feature Pipeline Status section at end with accurate counts
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    # 1. Query all pages from backend
    # 2. Find 'Feature Requests' page
    try:
        feature_requests = _find_page_by_title(final_state_backend, "Feature Requests")
        if not feature_requests:
            errors.append("[X] Feature Requests page not found")
        else:
            checks_passed.append("[C] Feature Requests page found")
    
        feature_requests_id = feature_requests.get("_id")
    
        # 3. Query all blocks for the page
        page_blocks = _get_blocks_for_page(final_state_backend, feature_requests_id)
    
        if not page_blocks:
            errors.append("[X] Feature Requests page has no blocks")
        else:
            checks_passed.append("[C] Feature Requests page has blocks")
    
        # Sort blocks by order
        page_blocks_sorted = sorted(page_blocks, key=lambda b: b.get("order", 0))
    
        # 4. Find green callout with implementation progress near top
        green_callout_found = False
        for block in page_blocks_sorted[:20]:  # Check first 20 blocks
            if block.get("type") == "callout":
                bg_color = block.get("properties", {}).get("backgroundColor", "").lower()
                content = block.get("content", "").lower()
            
                if "green" in bg_color and ("implementation progress" in content or "features completed" in content):
                    green_callout_found = True
                    break
    
        if not green_callout_found:
            errors.append("[X] Green callout with implementation progress not found at top")
        else:
            checks_passed.append("[C] Green callout with implementation progress found at top")
    
        # 5. Find 'Feature Pipeline Status' heading2 near end
        pipeline_heading_found = False
        for block in reversed(page_blocks_sorted[-30:]):  # Check last 30 blocks
            if block.get("type") == "heading2":
                content = block.get("content", "").lower()
                if "feature pipeline" in content or ("pipeline" in content and "status" in content):
                    pipeline_heading_found = True
                    break
    
        if not pipeline_heading_found:
            errors.append("[X] Feature Pipeline Status heading2 not found at end")
        else:
            checks_passed.append("[C] Feature Pipeline Status heading2 found at end")
    
        # 6. All checks passed
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_bug_tracker_swap_with_stats(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate Bug Tracker swap Critical/Medium with stats task.
    
    Verification:
    - Critical Bugs and Medium Priority sections are swapped
    - Red callout in new Critical section (which contains medium bugs)
    - Bug Statistics section at end with accurate counts
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    # 1. Query all pages from backend
    # 2. Find 'Bug Tracker' page
    try:
        bug_tracker = _find_page_by_title(final_state_backend, "Bug Tracker")
        if not bug_tracker:
            errors.append("[X] Bug Tracker page not found")
        else:
            checks_passed.append("[C] Bug Tracker page found")
    
        bug_tracker_id = bug_tracker.get("_id")
    
        # 3. Query all blocks for the page
        page_blocks = _get_blocks_for_page(final_state_backend, bug_tracker_id)
    
        if not page_blocks:
            errors.append("[X] Bug Tracker page has no blocks")
        else:
            checks_passed.append("[C] Bug Tracker page has blocks")
    
        # Sort blocks by order
        page_blocks_sorted = sorted(page_blocks, key=lambda b: b.get("order", 0))
    
        # 4. Find 'Critical Bugs' heading
        critical_heading = None
        for block in page_blocks_sorted:
            if block.get("type") in {"heading1", "heading2"}:
                content = block.get("content", "").lower()
                if "critical" in content and "bugs" in content:
                    critical_heading = block
                    break
    
        if not critical_heading:
            errors.append("[X] Critical Bugs heading not found")
        else:
            checks_passed.append("[C] Critical Bugs heading found")
    
        critical_order = critical_heading.get("order", 0)
    
        # 5. Find 'Medium Priority' heading
        medium_heading = None
        for block in page_blocks_sorted:
            if block.get("type") in {"heading1", "heading2"}:
                content = block.get("content", "").lower()
                if "medium" in content and "priority" in content:
                    medium_heading = block
                    break
    
        if not medium_heading:
            errors.append("[X] Medium Priority heading not found")
        else:
            checks_passed.append("[C] Medium Priority heading found")
    
        medium_order = medium_heading.get("order", 0)
    
        # 6. Verify Medium Priority now comes before Critical Bugs (swapped)
        if medium_order >= critical_order:
            errors.append(f"[X] Medium Priority should appear before Critical Bugs after swap (Medium: {medium_order}, Critical: {critical_order})")
        else:
            checks_passed.append(f"[C] Medium Priority should appear before Critical Bugs after swap (Medium: {medium_order}, Critical: {critical_order})")
    
        # 7. Find 'Bug Statistics' heading2 near end
        stats_heading_found = False
        for block in reversed(page_blocks_sorted[-20:]):  # Check last 20 blocks
            if block.get("type") == "heading2":
                content = block.get("content", "").lower()
                if "bug statistics" in content or ("bug" in content and "statistics" in content):
                    stats_heading_found = True
                    break
    
        if not stats_heading_found:
            errors.append("[X] Bug Statistics heading2 not found at end")
        else:
            checks_passed.append("[C] Bug Statistics heading2 found at end")
    
        # 8. All checks passed
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_bug_tracker_priority_legend(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate Bug Tracker Priority Legend task.
    
    Verification:
    - 'Bug Priority Legend' heading2 at beginning of page
    - Three callouts in order: red (Critical), orange (High), green (Low)
    - Red callouts added above unchecked todos containing 'urgent' or 'critical'
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    # 1. Query all pages from backend
    # 2. Find 'Bug Tracker' page
    try:
        bug_tracker = _find_page_by_title(final_state_backend, "Bug Tracker")
        if not bug_tracker:
            errors.append("[X] Bug Tracker page not found")
        else:
            checks_passed.append("[C] Bug Tracker page found")
    
        bug_tracker_id = bug_tracker.get("_id")
    
        # 3. Query all blocks for the page
        page_blocks = _get_blocks_for_page(final_state_backend, bug_tracker_id)
    
        if not page_blocks:
            errors.append("[X] Bug Tracker page has no blocks")
        else:
            checks_passed.append("[C] Bug Tracker page has blocks")
    
        # Sort blocks by order
        page_blocks_sorted = sorted(page_blocks, key=lambda b: b.get("order", 0))
    
        # 4. Find 'Bug Priority Legend' heading2 near beginning
        legend_heading = None
        for block in page_blocks_sorted[:20]:  # Check first 20 blocks
            if block.get("type") == "heading2":
                content = block.get("content", "").lower()
                if "bug priority legend" in content or ("priority" in content and "legend" in content):
                    legend_heading = block
                    break
    
        if not legend_heading:
            errors.append("[X] Bug Priority Legend heading2 not found at beginning of page")
        else:
            checks_passed.append("[C] Bug Priority Legend heading2 found at beginning of page")
    
        legend_order = legend_heading.get("order", 0)
    
        # 5. Find three callouts after legend heading with correct colors
        callouts_after_legend = []
        for block in page_blocks_sorted:
            if block.get("type") == "callout" and block.get("order", 0) > legend_order:
                callouts_after_legend.append(block)
                if len(callouts_after_legend) >= 3:
                    break
    
        if len(callouts_after_legend) < 3:
            errors.append(f"[X] Expected at least 3 callout blocks for legend (found: {len(callouts_after_legend)})")
        else:
            checks_passed.append(f"[C] Expected at least 3 callout blocks for legend (found: {len(callouts_after_legend)})")
    
        # 6. Check callout colors
        first_callout_color = callouts_after_legend[0].get("properties", {}).get("backgroundColor", "").lower()
        second_callout_color = callouts_after_legend[1].get("properties", {}).get("backgroundColor", "").lower()
        third_callout_color = callouts_after_legend[2].get("properties", {}).get("backgroundColor", "").lower()
    
        if "red" not in first_callout_color:
            errors.append(f"[X] First legend callout should be red (found: '{first_callout_color}')")
        else:
            checks_passed.append(f"[C] First legend callout should be red (found: '{first_callout_color}')")
    
        if "orange" not in second_callout_color:
            errors.append(f"[X] Second legend callout should be orange (found: '{second_callout_color}')")
        else:
            checks_passed.append(f"[C] Second legend callout should be orange (found: '{second_callout_color}')")
    
        if "green" not in third_callout_color:
            errors.append(f"[X] Third legend callout should be green (found: '{third_callout_color}')")
        else:
            checks_passed.append(f"[C] Third legend callout should be green (found: '{third_callout_color}')")
    
        # 7. All checks passed
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_code_examples_devops_section_2(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate Code Examples DevOps section with blue callout at top.
    
    Verification:
    - DevOps Examples heading2 after Rust Examples
    - Code block with 'yaml' language containing CI/CD pipeline code
    - Paragraph about CI/CD pattern
    - Blue callout at top of page (after main heading, before Javascript Examples) showing total code examples and languages
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    # 1. Query all pages from backend
    # 2. Find 'Code Examples Repository' page
    try:
        code_examples = _find_page_by_title(final_state_backend, "Code Examples Repository")
        if not code_examples:
            errors.append("[X] Code Examples Repository page not found")
        else:
            checks_passed.append("[C] Code Examples Repository page found")
    
        code_examples_id = code_examples.get("_id")
    
        # 3. Query all blocks for the page
        page_blocks = _get_blocks_for_page(final_state_backend, code_examples_id)
    
        if not page_blocks:
            errors.append("[X] Code Examples Repository page has no blocks")
        else:
            checks_passed.append("[C] Code Examples Repository page has blocks")
    
        # Sort blocks by order
        page_blocks_sorted = sorted(page_blocks, key=lambda b: b.get("order", 0))
    
        # 4. Find 'Rust Examples' heading2
        rust_heading = None
        for block in page_blocks_sorted:
            if block.get("type") == "heading2":
                content = block.get("content", "").lower()
                if "rust" in content and "examples" in content:
                    rust_heading = block
                    break
    
        if not rust_heading:
            errors.append("[X] Rust Examples heading2 not found")
        else:
            checks_passed.append("[C] Rust Examples heading2 found")
    
        rust_order = rust_heading.get("order", 0)
    
        # 5. Find 'DevOps Examples' heading2 after Rust
        devops_heading = None
        for block in page_blocks_sorted:
            if block.get("type") == "heading2" and block.get("order", 0) > rust_order:
                content = block.get("content", "").lower()
                if "devops" in content and "examples" in content:
                    devops_heading = block
                    break
    
        if not devops_heading:
            errors.append("[X] DevOps Examples heading2 not found after Rust Examples")
        else:
            checks_passed.append("[C] DevOps Examples heading2 found after Rust Examples")
    
        devops_order = devops_heading.get("order", 0)
    
        # 6. Find yaml code block after DevOps heading
        yaml_code_found = False
        for block in page_blocks_sorted:
            if block.get("type") == "code" and block.get("order", 0) > devops_order:
                lang = block.get("properties", {}).get("language", "").lower()
                content = block.get("content", "")
            
                if lang == "yaml" and ("ci" in content.lower() or "pipeline" in content.lower() or "jobs:" in content):
                    yaml_code_found = True
                    break
    
        if not yaml_code_found:
            errors.append("[X] YAML code block with CI/CD pipeline not found")
        else:
            checks_passed.append("[C] YAML code block with CI/CD pipeline found")
    
        # 7. Find blue callout at top of page showing stats
        blue_callout_found = False
        for block in page_blocks_sorted[:15]:  # Check first 15 blocks
            if block.get("type") == "callout":
                bg_color = block.get("properties", {}).get("backgroundColor", "").lower()
                content = block.get("content", "").lower()
            
                if "blue" in bg_color and ("code examples" in content or "programming languages" in content):
                    blue_callout_found = True
                    break
    
        if not blue_callout_found:
            errors.append("[X] Blue callout with repository stats not found at top of page")
        else:
            checks_passed.append("[C] Blue callout with repository stats found at top of page")
    
        # 8. All checks passed
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_getting_started_enhanced_onboarding_2(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate Getting Started Enhanced Onboarding task.
    
    Verification:
    - Section added after last checklist todo, before Key Features
    - Divider precedes the section
    - Dynamic callout (green if >50% complete, yellow otherwise)
    - heading3 'Next Steps' with paragraph
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    # 1. Query all pages from backend
    # 2. Find 'Getting Started' page
    try:
        getting_started = _find_page_by_title(final_state_backend, "Getting Started")
        if not getting_started:
            errors.append("[X] Getting Started page not found")
        else:
            checks_passed.append("[C] Getting Started page found")
    
        getting_started_id = getting_started.get("_id")
    
        # 3. Query all blocks for the page
        page_blocks = _get_blocks_for_page(final_state_backend, getting_started_id)
    
        if not page_blocks:
            errors.append("[X] Getting Started page has no blocks")
        else:
            checks_passed.append("[C] Getting Started page has blocks")
    
        # Sort blocks by order
        page_blocks_sorted = sorted(page_blocks, key=lambda b: b.get("order", 0))
    
        # 4. Find 'Quick Start Checklist' heading
        checklist_heading = None
        for block in page_blocks_sorted:
            if block.get("type") in {"heading1", "heading2"}:
                content = block.get("content", "").lower()
                if "quick start" in content and "checklist" in content:
                    checklist_heading = block
                    break
    
        if not checklist_heading:
            errors.append("[X] Quick Start Checklist heading not found")
        else:
            checks_passed.append("[C] Quick Start Checklist heading found")
    
        checklist_order = checklist_heading.get("order", 0)
    
        # 5. Count completion percentage
        checklist_todos = []
        for block in page_blocks_sorted:
            order = block.get("order", 0)
            if order > checklist_order and block.get("type") == "todo":
                checklist_todos.append(block)
            elif len(checklist_todos) > 0 and block.get("type") in {"heading1", "heading2"}:
                break
    
        if not checklist_todos:
            errors.append("[X] No todos found in checklist")
        else:
            checks_passed.append("[C] todos found in checklist")
    
        checked_count = sum(1 for t in checklist_todos if t.get("properties", {}).get("checked") == True)
        completion_percentage = (checked_count / len(checklist_todos) * 100) if checklist_todos else 0
    
        # 6. Find divider after checklist
        divider_found = False
        for block in page_blocks_sorted:
            if block.get("type") == "divider" and block.get("order", 0) > checklist_order:
                divider_found = True
                break
    
        if not divider_found:
            errors.append("[X] Divider not found after checklist section")
        else:
            checks_passed.append("[C] Divider found after checklist section")
    
        # 7. Find callout with appropriate color
        expected_color = "green" if completion_percentage > 50 else "yellow"
        callout_found = False
    
        for block in page_blocks_sorted:
            if block.get("type") == "callout" and block.get("order", 0) > checklist_order:
                bg_color = block.get("properties", {}).get("backgroundColor", "").lower()
                content = block.get("content", "").lower()
            
                if expected_color in bg_color and ("progress" in content or "completed" in content):
                    callout_found = True
                    break
    
        if not callout_found:
            errors.append(f"[X] Callout with {expected_color} background not found")
        else:
            checks_passed.append(f"[C] Callout with {expected_color} background found")
    
        # 8. Find 'Next Steps' heading3
        next_steps_found = False
        for block in page_blocks_sorted:
            if block.get("type") == "heading3" and block.get("order", 0) > checklist_order:
                content = block.get("content", "").lower()
                if "next steps" in content:
                    next_steps_found = True
                    break
    
        if not next_steps_found:
            errors.append("[X] Next Steps heading3 not found")
        else:
            checks_passed.append("[C] Next Steps heading3 found")
    
        # 9. All checks passed
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_code_examples_go_after_python_with_stats(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate Code Examples Go after Python with stats at end.
    
    Verification:
    - Go Examples section immediately after Python Examples
    - Code block with 'go' language containing goroutine/channel code
    - Paragraph about Go patterns
    - At end of page: divider, heading2 'Language Coverage Statistics'
    - Gray callout with coverage list showing 4 languages
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    # 1. Query all pages from backend
    # 2. Find 'Code Examples Repository' page
    try:
        code_examples = _find_page_by_title(final_state_backend, "Code Examples Repository")
        if not code_examples:
            errors.append("[X] Code Examples Repository page not found")
        else:
            checks_passed.append("[C] Code Examples Repository page found")
    
        code_examples_id = code_examples.get("_id")
    
        # 3. Query all blocks for the page
        page_blocks = _get_blocks_for_page(final_state_backend, code_examples_id)
    
        if not page_blocks:
            errors.append("[X] Code Examples Repository page has no blocks")
        else:
            checks_passed.append("[C] Code Examples Repository page has blocks")
    
        # Sort blocks by order
        page_blocks_sorted = sorted(page_blocks, key=lambda b: b.get("order", 0))
    
        # 4. Find 'Python Examples' heading2
        python_heading = None
        for block in page_blocks_sorted:
            if block.get("type") == "heading2":
                content = block.get("content", "").lower()
                if "python" in content and "examples" in content:
                    python_heading = block
                    break
    
        if not python_heading:
            errors.append("[X] Python Examples heading2 not found")
        else:
            checks_passed.append("[C] Python Examples heading2 found")
    
        python_order = python_heading.get("order", 0)
    
        # 5. Find 'Go Examples' heading2 after Python
        go_heading = None
        for block in page_blocks_sorted:
            if block.get("type") == "heading2" and block.get("order", 0) > python_order:
                content = block.get("content", "").lower()
                if "go" in content and "examples" in content:
                    go_heading = block
                    break
    
        if not go_heading:
            errors.append("[X] Go Examples heading2 not found after Python Examples")
        else:
            checks_passed.append("[C] Go Examples heading2 found after Python Examples")
    
        go_order = go_heading.get("order", 0)
    
        # 6. Find Go code block with goroutine/channel code
        go_code_found = False
        for block in page_blocks_sorted:
            if block.get("type") == "code" and block.get("order", 0) > go_order:
                lang = block.get("properties", {}).get("language", "").lower()
                content = block.get("content", "")
            
                if lang == "go" and ("goroutine" in content.lower() or "chan" in content or "make(chan" in content):
                    go_code_found = True
                    break
    
        if not go_code_found:
            errors.append("[X] Go code block with goroutine/channel code not found")
        else:
            checks_passed.append("[C] Go code block with goroutine/channel code found")
    
        # 7. Find 'Language Coverage Statistics' heading2 (should be near end)
        stats_heading = None
        for block in reversed(page_blocks_sorted):
            if block.get("type") == "heading2":
                content = block.get("content", "").lower()
                if "language" in content and ("coverage" in content or "statistics" in content):
                    stats_heading = block
                    break
    
        if not stats_heading:
            errors.append("[X] Language Coverage Statistics heading2 not found")
        else:
            checks_passed.append("[C] Language Coverage Statistics heading2 found")
    
        stats_order = stats_heading.get("order", 0)
    
        # 8. Find divider before stats section
        divider_found = False
        for block in page_blocks_sorted:
            if block.get("type") == "divider":
                divider_order = block.get("order", 0)
                if stats_order - 5 < divider_order < stats_order:
                    divider_found = True
                    break
    
        if not divider_found:
            errors.append("[X] Divider not found before Language Coverage Statistics")
        else:
            checks_passed.append("[C] Divider found before Language Coverage Statistics")
    
        # 9. Find gray callout with coverage information
        callout_found = False
        for block in page_blocks_sorted:
            if block.get("type") == "callout" and block.get("order", 0) > stats_order:
                bg_color = block.get("properties", {}).get("backgroundColor", "").lower()
                content = block.get("content", "").lower()
            
                if "gray" in bg_color and ("languages" in content or "covered" in content):
                    callout_found = True
                    break
    
        if not callout_found:
            errors.append("[X] Gray callout with language coverage not found")
        else:
            checks_passed.append("[C] Gray callout with language coverage found")
    
        # 10. All checks passed
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_sprint_planning_metrics(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate Sprint Planning Sprint Metrics section task.
    
    Verification:
    - Sprint Metrics heading2 after Bob's todo
    - Yellow callout with Sprint Health Check
    - Bulleted list with 3 items showing metrics
    - Divider followed by heading3 'Next Sprint Preview'
    - Exactly 3 unchecked todos for next sprint
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    # 1. Find 'Sprint Planning - Jan 15' page
    try:
        sprint_page = _find_page_with_all_title_patterns(final_state_backend, ["sprint planning", "jan"])
        if not sprint_page:
            errors.append("[X] Sprint Planning - Jan 15 page not found")
        else:
            checks_passed.append("[C] Sprint Planning - Jan 15 page found")

        sprint_page_id = sprint_page.get("_id")

        # 2. Query all blocks for the page
        page_blocks = _get_blocks_for_page(final_state_backend, sprint_page_id)
    
        if not page_blocks:
            errors.append("[X] Sprint Planning page has no blocks")
        else:
            checks_passed.append("[C] Sprint Planning page has blocks")
    
        # Sort blocks by order
        page_blocks_sorted = sorted(page_blocks, key=lambda b: b.get("order", 0))
    
        # 4. Find 'Sprint Metrics' heading2
        metrics_heading = None
        for block in page_blocks_sorted:
            if block.get("type") == "heading2":
                content = block.get("content", "").lower()
                if "sprint" in content and "metrics" in content:
                    metrics_heading = block
                    break
    
        if not metrics_heading:
            errors.append("[X] Sprint Metrics heading2 not found")
        else:
            checks_passed.append("[C] Sprint Metrics heading2 found")
    
        metrics_order = metrics_heading.get("order", 0)
    
        # 5. Find yellow callout with Sprint Health Check
        callout_found = False
        for block in page_blocks_sorted:
            if block.get("type") == "callout" and block.get("order", 0) > metrics_order:
                bg_color = block.get("properties", {}).get("backgroundColor", "").lower()
                content = block.get("content", "").lower()
            
                if "yellow" in bg_color and "sprint health check" in content:
                    callout_found = True
                    break
    
        if not callout_found:
            errors.append("[X] Yellow callout with Sprint Health Check not found")
        else:
            checks_passed.append("[C] Yellow callout with Sprint Health Check found")
    
        # 6. Find 'Next Sprint Preview' heading3
        preview_heading_found = False
        for block in page_blocks_sorted:
            if block.get("type") == "heading3" and block.get("order", 0) > metrics_order:
                content = block.get("content", "").lower()
                if "next sprint" in content and "preview" in content:
                    preview_heading_found = True
                    break
    
        if not preview_heading_found:
            errors.append("[X] Next Sprint Preview heading3 not found")
        else:
            checks_passed.append("[C] Next Sprint Preview heading3 found")
    
        # 7. All checks passed
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_weekly_standup_location_updates(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate Weekly Standup Location Updates task.
    
    Verification:
    - Divider after 'Blockers' heading
    - 'Location Updates' heading2 follows divider
    - Exactly 3 unchecked todos with location-related text
    - Blue callout at end showing task completion rate
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    # 1. Query all pages from backend
    # 2. Find 'Weekly Standup Template' page
    try:
        standup = _find_page_by_title(final_state_backend, "Weekly Standup Template")
        if not standup:
            errors.append("[X] Weekly Standup Template page not found")
        else:
            checks_passed.append("[C] Weekly Standup Template page found")
    
        standup_id = standup.get("_id")
    
        # 3. Query all blocks for the page
        page_blocks = _get_blocks_for_page(final_state_backend, standup_id)
    
        if not page_blocks:
            errors.append("[X] Weekly Standup Template page has no blocks")
        else:
            checks_passed.append("[C] Weekly Standup Template page has blocks")
    
        # Sort blocks by order
        page_blocks_sorted = sorted(page_blocks, key=lambda b: b.get("order", 0))
    
        # 4. Find 'Blockers' heading
        blockers_heading = None
        for block in page_blocks_sorted:
            if block.get("type") in {"heading1", "heading2", "heading3"}:
                content = block.get("content", "").lower()
                if "blockers" in content:
                    blockers_heading = block
                    break
    
        if not blockers_heading:
            errors.append("[X] Blockers heading not found")
        else:
            checks_passed.append("[C] Blockers heading found")
    
        blockers_order = blockers_heading.get("order", 0)
    
        # 5. Find 'Location Updates' heading2
        location_heading = None
        for block in page_blocks_sorted:
            if block.get("type") == "heading2" and block.get("order", 0) > blockers_order:
                content = block.get("content", "").lower()
                if "location" in content and "updates" in content:
                    location_heading = block
                    break
    
        if not location_heading:
            errors.append("[X] Location Updates heading2 not found")
        else:
            checks_passed.append("[C] Location Updates heading2 found")
    
        location_order = location_heading.get("order", 0)
    
        # 6. Count todos after Location Updates heading
        location_todos = []
        for block in page_blocks_sorted:
            if block.get("type") == "todo" and location_order < block.get("order", 0):
                location_todos.append(block)
                if len(location_todos) >= 3:
                    break
    
        if len(location_todos) < 3:
            errors.append(f"[X] Expected at least 3 location update todos (found: {len(location_todos)})")
        else:
            checks_passed.append(f"[C] Expected at least 3 location update todos (found: {len(location_todos)})")
    
        # 7. Find blue callout at end with task completion
        callout_found = False
        for block in reversed(page_blocks_sorted):
            if block.get("type") == "callout":
                bg_color = block.get("properties", {}).get("backgroundColor", "").lower()
                content = block.get("content", "").lower()
            
                if "blue" in bg_color and ("task completion" in content or "tasks completed" in content):
                    callout_found = True
                    break
    
        if not callout_found:
            errors.append("[X] Blue callout with task completion rate not found at end")
        else:
            checks_passed.append("[C] Blue callout with task completion rate found at end")
    
        # 8. All checks passed
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_bug_tracker_under_investigation(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate Bug Tracker Under Investigation section task.
    
    Verification:
    - 'Under Investigation' heading2 between Medium and Low Priority
    - Orange callout with warning icon and debug message
    - Summary paragraph with accurate bug counts for each priority level
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    # 1. Query all pages from backend
    # 2. Find 'Bug Tracker' page
    try:
        bug_tracker = _find_page_by_title(final_state_backend, "Bug Tracker")
        if not bug_tracker:
            errors.append("[X] Bug Tracker page not found")
        else:
            checks_passed.append("[C] Bug Tracker page found")
    
        bug_tracker_id = bug_tracker.get("_id")
    
        # 3. Query all blocks for the page
        page_blocks = _get_blocks_for_page(final_state_backend, bug_tracker_id)
    
        if not page_blocks:
            errors.append("[X] Bug Tracker page has no blocks")
        else:
            checks_passed.append("[C] Bug Tracker page has blocks")
    
        # Sort blocks by order
        page_blocks_sorted = sorted(page_blocks, key=lambda b: b.get("order", 0))
    
        # 4. Find 'Medium Priority' heading
        medium_heading = None
        for block in page_blocks_sorted:
            if block.get("type") in {"heading1", "heading2"}:
                content = block.get("content", "").lower()
                if "medium" in content and "priority" in content:
                    medium_heading = block
                    break
    
        if not medium_heading:
            errors.append("[X] Medium Priority heading not found")
        else:
            checks_passed.append("[C] Medium Priority heading found")
    
        medium_order = medium_heading.get("order", 0)
    
        # 5. Find 'Low Priority' heading
        low_heading = None
        for block in page_blocks_sorted:
            if block.get("type") in {"heading1", "heading2"} and block.get("order", 0) > medium_order:
                content = block.get("content", "").lower()
                if "low" in content and "priority" in content:
                    low_heading = block
                    break
    
        if not low_heading:
            errors.append("[X] Low Priority heading not found")
        else:
            checks_passed.append("[C] Low Priority heading found")
    
        low_order = low_heading.get("order", 0)
    
        # 6. Find 'Under Investigation' heading2
        investigation_heading = None
        for block in page_blocks_sorted:
            if block.get("type") == "heading2":
                order = block.get("order", 0)
                if medium_order < order < low_order:
                    content = block.get("content", "").lower()
                    if "under investigation" in content:
                        investigation_heading = block
                        break
    
        if not investigation_heading:
            errors.append("[X] Under Investigation heading2 not found between Medium and Low Priority")
        else:
            checks_passed.append("[C] Under Investigation heading2 found between Medium and Low Priority")
    
        investigation_order = investigation_heading.get("order", 0)
    
        # 7. Find orange callout
        callout_found = False
        for block in page_blocks_sorted:
            if block.get("type") == "callout":
                order = block.get("order", 0)
                if investigation_order < order < low_order:
                    bg_color = block.get("properties", {}).get("backgroundColor", "").lower()
                    content = block.get("content", "").lower()
                
                    if "orange" in bg_color and ("bugs" in content and ("debugged" in content or "evaluated" in content)):
                        callout_found = True
                        break
    
        if not callout_found:
            errors.append("[X] Orange callout with investigation message not found")
        else:
            checks_passed.append("[C] Orange callout with investigation message found")
    
        # 8. All checks passed
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_onboarding_guide_first_week_milestones(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate Onboarding Guide First Week Milestones task.
    
    Verification:
    - 'First Week Milestones' heading2 after numbered list section
    - Exactly 5 todo blocks with specific milestones
    - First two todos checked, last three unchecked
    - Green callout with completion message
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    # 1. Query all pages from backend
    # 2. Find 'Onboarding Guide' page
    try:
        onboarding = _find_page_by_title(final_state_backend, "Onboarding Guide")
        if not onboarding:
            errors.append("[X] Onboarding Guide page not found")
        else:
            checks_passed.append("[C] Onboarding Guide page found")
    
        onboarding_id = onboarding.get("_id")
    
        # 3. Query all blocks for the page
        page_blocks = _get_blocks_for_page(final_state_backend, onboarding_id)
    
        if not page_blocks:
            errors.append("[X] Onboarding Guide page has no blocks")
        else:
            checks_passed.append("[C] Onboarding Guide page has blocks")
    
        # Sort blocks by order
        page_blocks_sorted = sorted(page_blocks, key=lambda b: b.get("order", 0))
    
        # 4. Find 'First Week Milestones' heading2
        milestones_heading = None
        for block in page_blocks_sorted:
            if block.get("type") == "heading2":
                content = block.get("content", "").lower()
                if "first week" in content and "milestones" in content:
                    milestones_heading = block
                    break
    
        if not milestones_heading:
            errors.append("[X] First Week Milestones heading2 not found")
        else:
            checks_passed.append("[C] First Week Milestones heading2 found")
    
        milestones_order = milestones_heading.get("order", 0)
    
        # 5. Find todos after milestones heading
        milestone_todos = []
        for block in page_blocks_sorted:
            if block.get("type") == "todo" and block.get("order", 0) > milestones_order:
                milestone_todos.append(block)
            elif len(milestone_todos) > 0 and block.get("type") in {"heading1", "heading2", "callout"}:
                break
    
        if len(milestone_todos) < 5:
            errors.append(f"[X] Expected at least 5 milestone todos (found: {len(milestone_todos)})")
        else:
            checks_passed.append(f"[C] Expected at least 5 milestone todos (found: {len(milestone_todos)})")
    
        # 6. Check first two are checked, last three unchecked
        first_five = milestone_todos[:5]
        first_two_checked = all(t.get("properties", {}).get("checked") == True for t in first_five[:2])
        last_three_unchecked = all(not t.get("properties", {}).get("checked") for t in first_five[2:5])
    
        if not first_two_checked:
            errors.append("[X] First two milestone todos should be checked")
        else:
            checks_passed.append("[C] First two milestone todos should be checked")
    
        if not last_three_unchecked:
            errors.append("[X] Last three milestone todos should be unchecked")
        else:
            checks_passed.append("[C] Last three milestone todos should be unchecked")
    
        # 7. Find green callout
        callout_found = False
        for block in page_blocks_sorted:
            if block.get("type") == "callout" and block.get("order", 0) > milestones_order:
                bg_color = block.get("properties", {}).get("backgroundColor", "").lower()
                content = block.get("content", "").lower()
            
                if "green" in bg_color and ("milestones" in content or "onboarding" in content):
                    callout_found = True
                    break
    
        if not callout_found:
            errors.append("[X] Green callout with completion message not found")
        else:
            checks_passed.append("[C] Green callout with completion message found")
    
        # 8. All checks passed
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_code_examples_python_guide(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate Code Examples Python Guide task.
    
    Verification:
    - Guide section between Python Examples heading and first code block
    - Yellow callout with usage guide
    - heading3 'Running the Examples'
    - Numbered list with 3 items
    - Divider and italic paragraph with note
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    # 1. Query all pages from backend
    # 2. Find 'Code Examples Repository' page
    try:
        code_examples = _find_page_by_title(final_state_backend, "Code Examples Repository")
        if not code_examples:
            errors.append("[X] Code Examples Repository page not found")
        else:
            checks_passed.append("[C] Code Examples Repository page found")
    
        code_examples_id = code_examples.get("_id")
    
        # 3. Query all blocks for the page
        page_blocks = _get_blocks_for_page(final_state_backend, code_examples_id)
    
        if not page_blocks:
            errors.append("[X] Code Examples Repository page has no blocks")
        else:
            checks_passed.append("[C] Code Examples Repository page has blocks")
    
        # Sort blocks by order
        page_blocks_sorted = sorted(page_blocks, key=lambda b: b.get("order", 0))
    
        # 4. Find 'Python Examples' heading2
        python_heading = None
        for block in page_blocks_sorted:
            if block.get("type") == "heading2":
                content = block.get("content", "").lower()
                if "python" in content and "examples" in content:
                    python_heading = block
                    break
    
        if not python_heading:
            errors.append("[X] Python Examples heading2 not found")
        else:
            checks_passed.append("[C] Python Examples heading2 found")
    
        python_order = python_heading.get("order", 0)
    
        # 5. Find first code block after Python heading
        first_code_order = None
        for block in page_blocks_sorted:
            if block.get("type") == "code" and block.get("order", 0) > python_order:
                first_code_order = block.get("order", 0)
                break
    
        if not first_code_order:
            errors.append("[X] No code block found after Python Examples heading")
        else:
            checks_passed.append("[C] code block found after Python Examples heading")
    
        # 6. Find yellow callout between heading and code
        callout_found = False
        for block in page_blocks_sorted:
            order = block.get("order", 0)
            if python_order < order < first_code_order:
                if block.get("type") == "callout":
                    bg_color = block.get("properties", {}).get("backgroundColor", "").lower()
                    content = block.get("content", "").lower()
                
                    if "yellow" in bg_color and "usage guide" in content:
                        callout_found = True
                        break
    
        if not callout_found:
            errors.append("[X] Yellow callout with Usage Guide not found")
        else:
            checks_passed.append("[C] Yellow callout with Usage Guide found")
    
        # 7. Find 'Running the Examples' heading3
        running_heading_found = False
        for block in page_blocks_sorted:
            order = block.get("order", 0)
            if python_order < order < first_code_order:
                if block.get("type") == "heading3":
                    content = block.get("content", "").lower()
                    if "running" in content and "examples" in content:
                        running_heading_found = True
                        break
    
        if not running_heading_found:
            errors.append("[X] Running the Examples heading3 not found")
        else:
            checks_passed.append("[C] Running the Examples heading3 found")
    
        # 8. Find numbered list
        numbered_lists = [
            b for b in page_blocks_sorted 
            if b.get("type") == "numberedList" and python_order < b.get("order", 0) < first_code_order
        ]
    
        if len(numbered_lists) < 3:
            errors.append(f"[X] Expected at least 3 numbered list items (found: {len(numbered_lists)})")
        else:
            checks_passed.append(f"[C] Expected at least 3 numbered list items (found: {len(numbered_lists)})")
    
        # 9. Find divider and italic paragraph
        divider_found = any(
            b.get("type") == "divider" 
            for b in page_blocks_sorted 
            if python_order < b.get("order", 0) < first_code_order
        )
    
        if not divider_found:
            errors.append("[X] Divider not found in guide section")
        else:
            checks_passed.append("[C] Divider found in guide section")
    
        # 10. All checks passed
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_product_requirements_security_considerations(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate Product Requirements Security Considerations task.
    
    Verification:
    - Security Considerations heading3 after Technical Requirements Part 3
    - Paragraph with security requirements intro
    - Exactly 5 bulleted list items with security requirements
    - Yellow callout with warning icon about security review
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    # 1. Query all pages from backend
    # 2. Find 'Comprehensive Product Requirements Document' page
    try:
        product_req_doc = _find_page_by_title(final_state_backend, "Comprehensive Product Requirements")
        if not product_req_doc:
            errors.append("[X] Comprehensive Product Requirements Document page not found")
        else:
            checks_passed.append("[C] Comprehensive Product Requirements Document page found")
    
        product_req_doc_id = product_req_doc.get("_id")
    
        # 3. Query all blocks for the page
        page_blocks = _get_blocks_for_page(final_state_backend, product_req_doc_id)
    
        if not page_blocks:
            errors.append("[X] Comprehensive Product Requirements Document page has no blocks")
        else:
            checks_passed.append("[C] Comprehensive Product Requirements Document page has blocks")
    
        # Sort blocks by order
        page_blocks_sorted = sorted(page_blocks, key=lambda b: b.get("order", 0))
    
        # 4. Find 'Technical Requirements - Part 3' heading3
        part3_heading = None
        for block in page_blocks_sorted:
            if block.get("type") == "heading3":
                content = block.get("content", "").lower()
                if "technical requirements" in content and "part 3" in content:
                    part3_heading = block
                    break
    
        if not part3_heading:
            errors.append("[X] Technical Requirements - Part 3 heading3 not found")
        else:
            checks_passed.append("[C] Technical Requirements - Part 3 heading3 found")
    
        part3_order = part3_heading.get("order", 0)
    
        # 5. Find 'Security Considerations' heading3
        security_heading = None
        for block in page_blocks_sorted:
            if block.get("type") == "heading3" and block.get("order", 0) > part3_order:
                content = block.get("content", "").lower()
                if "security" in content and "considerations" in content:
                    security_heading = block
                    break
    
        if not security_heading:
            errors.append("[X] Security Considerations heading3 not found")
        else:
            checks_passed.append("[C] Security Considerations heading3 found")
    
        security_order = security_heading.get("order", 0)
    
        # 6. Find paragraph after security heading
        paragraph_found = False
        for block in page_blocks_sorted:
            if block.get("type") == "paragraph" and security_order < block.get("order", 0):
                content = block.get("content", "").lower()
                if "security" in content and "requirements" in content:
                    paragraph_found = True
                    break
                elif block.get("type") in {"heading1", "heading2", "heading3"}:
                    break
    
        if not paragraph_found:
            errors.append("[X] Introductory paragraph about security requirements not found")
        else:
            checks_passed.append("[C] Introductory paragraph about security requirements found")
    
        # 7. Count bulleted list items in security section
        bulleted_lists = []
        for block in page_blocks_sorted:
            if block.get("type") == "bulletedList" and security_order < block.get("order", 0):
                bulleted_lists.append(block)
            elif len(bulleted_lists) > 0 and block.get("type") in {"heading2", "heading3", "callout"}:
                break
    
        if len(bulleted_lists) < 5:
            errors.append(f"[X] Expected at least 5 bulleted list items for security (found: {len(bulleted_lists)})")
        else:
            checks_passed.append(f"[C] Expected at least 5 bulleted list items for security (found: {len(bulleted_lists)})")
    
        # 8. Find yellow callout with security review message
        callout_found = False
        for block in page_blocks_sorted:
            if block.get("type") == "callout" and block.get("order", 0) > security_order:
                bg_color = block.get("properties", {}).get("backgroundColor", "").lower()
                content = block.get("content", "").lower()
            
                if "yellow" in bg_color and ("security review" in content or "security team" in content):
                    callout_found = True
                    break
    
        if not callout_found:
            errors.append("[X] Yellow callout with security review message not found")
        else:
            checks_passed.append("[C] Yellow callout with security review message found")
    
        # 9. All checks passed
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_feature_requests_under_review(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate Feature Requests Under Review section task.
    
    Verification:
    - 'Under Review' heading2 between High Priority and Community Suggestions
    - Orange callout with evaluation message
    - Exactly 3 unchecked todo blocks with specific features
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    # 1. Query all pages from backend
    # 2. Find 'Feature Requests' page
    try:
        feature_requests = _find_page_by_title(final_state_backend, "Feature Requests")
        if not feature_requests:
            errors.append("[X] Feature Requests page not found")
        else:
            checks_passed.append("[C] Feature Requests page found")
    
        feature_requests_id = feature_requests.get("_id")
    
        # 3. Query all blocks for the page
        page_blocks = _get_blocks_for_page(final_state_backend, feature_requests_id)
    
        if not page_blocks:
            errors.append("[X] Feature Requests page has no blocks")
        else:
            checks_passed.append("[C] Feature Requests page has blocks")
    
        # Sort blocks by order
        page_blocks_sorted = sorted(page_blocks, key=lambda b: b.get("order", 0))
    
        # 4. Find 'High Priority' heading
        high_priority_heading = None
        for block in page_blocks_sorted:
            if block.get("type") in {"heading1", "heading2"}:
                content = block.get("content", "").lower()
                if "high priority" in content:
                    high_priority_heading = block
                    break
    
        if not high_priority_heading:
            errors.append("[X] High Priority heading not found")
        else:
            checks_passed.append("[C] High Priority heading found")
    
        high_priority_order = high_priority_heading.get("order", 0)
    
        # 5. Find 'Community Suggestions' heading
        community_heading = None
        for block in page_blocks_sorted:
            if block.get("type") in {"heading1", "heading2"} and block.get("order", 0) > high_priority_order:
                content = block.get("content", "").lower()
                if "community" in content and "suggestions" in content:
                    community_heading = block
                    break
    
        if not community_heading:
            errors.append("[X] Community Suggestions heading not found")
        else:
            checks_passed.append("[C] Community Suggestions heading found")
    
        community_order = community_heading.get("order", 0)
    
        # 6. Find 'Under Review' heading2
        under_review_heading = None
        for block in page_blocks_sorted:
            if block.get("type") == "heading2":
                order = block.get("order", 0)
                if high_priority_order < order < community_order:
                    content = block.get("content", "").lower()
                    if "under review" in content:
                        under_review_heading = block
                        break
    
        if not under_review_heading:
            errors.append("[X] Under Review heading2 not found between High Priority and Community Suggestions")
        else:
            checks_passed.append("[C] Under Review heading2 found between High Priority and Community Suggestions")
    
        under_review_order = under_review_heading.get("order", 0)
    
        # 7. Find orange callout
        callout_found = False
        for block in page_blocks_sorted:
            if block.get("type") == "callout":
                order = block.get("order", 0)
                if under_review_order < order < community_order:
                    bg_color = block.get("properties", {}).get("backgroundColor", "").lower()
                    content = block.get("content", "").lower()
                
                    if "orange" in bg_color and ("features" in content and ("evaluated" in content or "product team" in content)):
                        callout_found = True
                        break
    
        if not callout_found:
            errors.append("[X] Orange callout with evaluation message not found")
        else:
            checks_passed.append("[C] Orange callout with evaluation message found")
    
        # 8. Count todos in Under Review section
        under_review_todos = []
        for block in page_blocks_sorted:
            if block.get("type") == "todo":
                order = block.get("order", 0)
                if under_review_order < order < community_order:
                    under_review_todos.append(block)
    
        if len(under_review_todos) < 3:
            errors.append(f"[X] Expected at least 3 todo items in Under Review section (found: {len(under_review_todos)})")
        else:
            checks_passed.append(f"[C] Expected at least 3 todo items in Under Review section (found: {len(under_review_todos)})")
    
        # 9. Verify todos are unchecked
        checked_todos = [t for t in under_review_todos if t.get("properties", {}).get("checked") == True]
        if checked_todos:
            errors.append(f"[X] All Under Review todos should be unchecked (found {len(checked_todos)} checked)")
        else:
            checks_passed.append(f"[C] All Under Review todos should be unchecked (found {len(checked_todos)} checked)")
    
        # 10. All checks passed
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_getting_started_progress_indicator(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate Getting Started Progress Indicator task.
    
    Verification:
    - Progress indicator after Quick Start Checklist, before Key Features
    - Callout with dynamic color based on completion percentage
    - Accurate task counts and percentage
    - Italic paragraph with today's date at bottom
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    # 1. Query all pages from backend
    # 2. Find 'Getting Started' page
    try:
        getting_started = _find_page_by_title(final_state_backend, "Getting Started")
        if not getting_started:
            errors.append("[X] Getting Started page not found")
        else:
            checks_passed.append("[C] Getting Started page found")
    
        getting_started_id = getting_started.get("_id")
    
        # 3. Query all blocks for the page
        page_blocks = _get_blocks_for_page(final_state_backend, getting_started_id)
    
        if not page_blocks:
            errors.append("[X] Getting Started page has no blocks")
        else:
            checks_passed.append("[C] Getting Started page has blocks")
    
        # Sort blocks by order
        page_blocks_sorted = sorted(page_blocks, key=lambda b: b.get("order", 0))
    
        # 4. Find 'Quick Start Checklist' heading
        checklist_heading = None
        for block in page_blocks_sorted:
            if block.get("type") in {"heading1", "heading2"}:
                content = block.get("content", "").lower()
                if "quick start" in content and "checklist" in content:
                    checklist_heading = block
                    break
    
        if not checklist_heading:
            errors.append("[X] Quick Start Checklist heading not found")
        else:
            checks_passed.append("[C] Quick Start Checklist heading found")
    
        checklist_order = checklist_heading.get("order", 0)
    
        # 5. Find 'Key Features' heading
        features_heading = None
        for block in page_blocks_sorted:
            if block.get("type") in {"heading1", "heading2"} and block.get("order", 0) > checklist_order:
                content = block.get("content", "").lower()
                if "key features" in content or "features" in content:
                    features_heading = block
                    break
    
        if not features_heading:
            errors.append("[X] Key Features heading not found")
        else:
            checks_passed.append("[C] Key Features heading found")
    
        features_order = features_heading.get("order", 0)
    
        # 6. Count todos in checklist section
        checklist_todos = []
        for block in page_blocks_sorted:
            order = block.get("order", 0)
            if checklist_order < order < features_order and block.get("type") == "todo":
                checklist_todos.append(block)
    
        if not checklist_todos:
            errors.append("[X] No todo blocks found in Quick Start Checklist section")
        else:
            checks_passed.append("[C] todo blocks found in Quick Start Checklist section")
    
        total_todos = len(checklist_todos)
        checked_todos = sum(1 for t in checklist_todos if t.get("properties", {}).get("checked") == True)
        completion_percentage = (checked_todos / total_todos * 100) if total_todos > 0 else 0
    
        # 7. Find progress callout
        callout_found = False
        expected_color = None
    
        if completion_percentage > 75:
            expected_color = "green"
        elif 25 <= completion_percentage <= 75:
            expected_color = "yellow"
        else:
            expected_color = "red"
    
        for block in page_blocks_sorted:
            if block.get("type") == "callout":
                order = block.get("order", 0)
                if checklist_order < order < features_order:
                    bg_color = block.get("properties", {}).get("backgroundColor", "").lower()
                    content = block.get("content", "").lower()
                
                    if expected_color in bg_color and ("onboarding progress" in content or "tasks completed" in content):
                        callout_found = True
                        break
    
        if not callout_found:
            errors.append(f"[X] Progress callout with {expected_color} background not found")
        else:
            checks_passed.append(f"[C] Progress callout with {expected_color} background found")
    
        # 8. All checks passed
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_sprint_planning_retrospective(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate Sprint Planning Retrospective section task.
    
    Verification:
    - Retrospective section added after Action Items
    - Divider before section
    - heading2 'Sprint Retrospective' with specific subsections
    - Completion percentage calculated from Action Items todos
    - Green callout with key learning
    - Next Sprint Focus section with numbered list
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    # 1. Find 'Sprint Planning - Jan 15' page
    try:
        sprint_page = _find_page_with_all_title_patterns(final_state_backend, ["sprint planning", "jan"])
        if not sprint_page:
            errors.append("[X] Sprint Planning - Jan 15 page not found")
        else:
            checks_passed.append("[C] Sprint Planning - Jan 15 page found")

        sprint_page_id = sprint_page.get("_id")

        # 2. Query all blocks for the page
        page_blocks = _get_blocks_for_page(final_state_backend, sprint_page_id)
    
        if not page_blocks:
            errors.append("[X] Sprint Planning page has no blocks")
        else:
            checks_passed.append("[C] Sprint Planning page has blocks")
    
        # Sort blocks by order
        page_blocks_sorted = sorted(page_blocks, key=lambda b: b.get("order", 0))
    
        # 4. Find 'Action Items' heading
        action_items_heading = None
        for block in page_blocks_sorted:
            if block.get("type") in {"heading1", "heading2", "heading3"}:
                content = block.get("content", "").lower()
                if "action" in content and "items" in content:
                    action_items_heading = block
                    break
    
        if not action_items_heading:
            errors.append("[X] Action Items heading not found")
        else:
            checks_passed.append("[C] Action Items heading found")
    
        action_items_order = action_items_heading.get("order", 0)
    
        # 5. Find 'Sprint Retrospective' heading2
        retrospective_heading = None
        for block in page_blocks_sorted:
            if block.get("type") == "heading2" and block.get("order", 0) > action_items_order:
                content = block.get("content", "").lower()
                if "sprint" in content and "retrospective" in content:
                    retrospective_heading = block
                    break
    
        if not retrospective_heading:
            errors.append("[X] Sprint Retrospective heading2 not found")
        else:
            checks_passed.append("[C] Sprint Retrospective heading2 found")
    
        retrospective_order = retrospective_heading.get("order", 0)
    
        # 6. Check divider exists before retrospective
        divider_found = False
        for block in page_blocks_sorted:
            if block.get("type") == "divider":
                divider_order = block.get("order", 0)
                if action_items_order < divider_order < retrospective_order:
                    divider_found = True
                    break
    
        if not divider_found:
            errors.append("[X] Divider not found before Sprint Retrospective")
        else:
            checks_passed.append("[C] Divider found before Sprint Retrospective")
    
        # 7. Find 'What Went Well' heading3
        went_well_found = False
        for block in page_blocks_sorted:
            if block.get("type") == "heading3" and block.get("order", 0) > retrospective_order:
                content = block.get("content", "").lower()
                if "went well" in content or "what went" in content:
                    went_well_found = True
                    break
    
        if not went_well_found:
            errors.append("[X] What Went Well heading3 not found")
        else:
            checks_passed.append("[C] What Went Well heading3 found")
    
        # 8. Find 'Areas for Improvement' heading3
        improvement_found = False
        for block in page_blocks_sorted:
            if block.get("type") == "heading3" and block.get("order", 0) > retrospective_order:
                content = block.get("content", "").lower()
                if "improvement" in content or "areas for" in content:
                    improvement_found = True
                    break
    
        if not improvement_found:
            errors.append("[X] Areas for Improvement heading3 not found")
        else:
            checks_passed.append("[C] Areas for Improvement heading3 found")
    
        # 9. Find green callout with key learning
        green_callout_found = False
        for block in page_blocks_sorted:
            if block.get("type") == "callout" and block.get("order", 0) > retrospective_order:
                bg_color = block.get("properties", {}).get("backgroundColor", "").lower()
                content = block.get("content", "").lower()
            
                if "green" in bg_color and ("key learning" in content or "learning" in content):
                    green_callout_found = True
                    break
    
        if not green_callout_found:
            errors.append("[X] Green callout with Key Learning not found")
        else:
            checks_passed.append("[C] Green callout with Key Learning found")
    
        # 10. Find 'Next Sprint Focus' heading3
        next_sprint_found = False
        for block in page_blocks_sorted:
            if block.get("type") == "heading3" and block.get("order", 0) > retrospective_order:
                content = block.get("content", "").lower()
                if "next sprint" in content and "focus" in content:
                    next_sprint_found = True
                    break
    
        if not next_sprint_found:
            errors.append("[X] Next Sprint Focus heading3 not found")
        else:
            checks_passed.append("[C] Next Sprint Focus heading3 found")
    
        # 11. All checks passed
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_sprint_planning_swap_with_metrics(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate Sprint Planning swap Goals/Action Items with metrics.
    
    Verification:
    - Sprint Goals and Action Items sections are swapped
    - Sprint Velocity Metrics heading2 after relocated Sprint Goals
    - Toggle block with Historical Performance
    - All original content intact
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    # 1. Find 'Sprint Planning - Jan 15' page
    try:
        sprint_page = _find_page_with_all_title_patterns(final_state_backend, ["sprint planning", "jan"])
        if not sprint_page:
            errors.append("[X] Sprint Planning - Jan 15 page not found")
        else:
            checks_passed.append("[C] Sprint Planning - Jan 15 page found")

        sprint_page_id = sprint_page.get("_id")

        # 2. Query all blocks for the page
        page_blocks = _get_blocks_for_page(final_state_backend, sprint_page_id)
    
        if not page_blocks:
            errors.append("[X] Sprint Planning page has no blocks")
        else:
            checks_passed.append("[C] Sprint Planning page has blocks")
    
        # Sort blocks by order
        page_blocks_sorted = sorted(page_blocks, key=lambda b: b.get("order", 0))
    
        # 4. Find Sprint Goals heading
        sprint_goals_heading = None
        for block in page_blocks_sorted:
            if block.get("type") in {"heading1", "heading2"}:
                content = block.get("content", "").lower()
                if "sprint" in content and "goals" in content:
                    sprint_goals_heading = block
                    break
    
        if not sprint_goals_heading:
            errors.append("[X] Sprint Goals heading not found")
        else:
            checks_passed.append("[C] Sprint Goals heading found")
    
        sprint_goals_order = sprint_goals_heading.get("order", 0)
    
        # 5. Find Action Items heading
        action_items_heading = None
        for block in page_blocks_sorted:
            if block.get("type") in {"heading1", "heading2"}:
                content = block.get("content", "").lower()
                if "action" in content and "items" in content:
                    action_items_heading = block
                    break
    
        if not action_items_heading:
            errors.append("[X] Action Items heading not found")
        else:
            checks_passed.append("[C] Action Items heading found")
    
        action_items_order = action_items_heading.get("order", 0)
    
        # 6. Verify Action Items now appears before Sprint Goals (swapped)
        if action_items_order >= sprint_goals_order:
            errors.append(f"[X] Action Items should appear before Sprint Goals after swap (Action: {action_items_order}, Goals: {sprint_goals_order})")
        else:
            checks_passed.append(f"[C] Action Items should appear before Sprint Goals after swap (Action: {action_items_order}, Goals: {sprint_goals_order})")
    
        # 7. Find 'Sprint Velocity Metrics' heading2
        velocity_heading = None
        for block in page_blocks_sorted:
            if block.get("type") == "heading2" and block.get("order", 0) > sprint_goals_order:
                content = block.get("content", "").lower()
                if "velocity" in content and "metrics" in content:
                    velocity_heading = block
                    break
    
        if not velocity_heading:
            errors.append("[X] Sprint Velocity Metrics heading2 not found after relocated Sprint Goals")
        else:
            checks_passed.append("[C] Sprint Velocity Metrics heading2 found after relocated Sprint Goals")
    
        # 8. Find toggle block with Historical Performance
        toggle_found = False
        for block in page_blocks_sorted:
            if block.get("type") == "toggle" and block.get("order", 0) > sprint_goals_order:
                content = block.get("content", "").lower()
                if "historical" in content and "performance" in content:
                    toggle_found = True
                    break
    
        if not toggle_found:
            errors.append("[X] Toggle block 'Historical Performance' not found")
        else:
            checks_passed.append("[C] Toggle block 'Historical Performance' found")
    
        # 9. All checks passed
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_weekly_standup_achievements(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate Weekly Standup Weekly Achievements task.
    
    Verification:
    - 'Weekly Achievements' heading2 after completed todos, before unchecked
    - Toggle block with completed items detail
    - Purple callout showing correct completed count
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    # 1. Query all pages from backend
    # 2. Find 'Weekly Standup Template' page
    try:
        standup = _find_page_by_title(final_state_backend, "Weekly Standup Template")
        if not standup:
            errors.append("[X] Weekly Standup Template page not found")
        else:
            checks_passed.append("[C] Weekly Standup Template page found")
    
        standup_id = standup.get("_id")
    
        # 3. Query all blocks for the page
        page_blocks = _get_blocks_for_page(final_state_backend, standup_id)
    
        if not page_blocks:
            errors.append("[X] Weekly Standup Template page has no blocks")
        else:
            checks_passed.append("[C] Weekly Standup Template page has blocks")
    
        # Sort blocks by order
        page_blocks_sorted = sorted(page_blocks, key=lambda b: b.get("order", 0))
    
        # 4. Count completed todos
        all_todos = [b for b in page_blocks if b.get("type") == "todo"]
        completed_todos = [t for t in all_todos if t.get("properties", {}).get("checked") == True]
        completed_count = len(completed_todos)
    
        # 5. Find 'Weekly Achievements' heading2
        achievements_heading = None
        for block in page_blocks_sorted:
            if block.get("type") == "heading2":
                content = block.get("content", "").lower()
                if "weekly" in content and "achievements" in content:
                    achievements_heading = block
                    break
    
        if not achievements_heading:
            errors.append("[X] Weekly Achievements heading2 not found")
        else:
            checks_passed.append("[C] Weekly Achievements heading2 found")
    
        achievements_order = achievements_heading.get("order", 0)
    
        # 6. Find toggle block
        toggle_found = False
        for block in page_blocks_sorted:
            if block.get("type") == "toggle" and block.get("order", 0) > achievements_order:
                content = block.get("content", "").lower()
                if "completed" in content and "items" in content and "detail" in content:
                    toggle_found = True
                    break
    
        if not toggle_found:
            errors.append("[X] Toggle block 'Completed Items Detail' not found")
        else:
            checks_passed.append("[C] Toggle block 'Completed Items Detail' found")
    
        # 7. Find purple callout with completion count
        purple_callout_found = False
        for block in page_blocks_sorted:
            if block.get("type") == "callout" and block.get("order", 0) > achievements_order:
                bg_color = block.get("properties", {}).get("backgroundColor", "").lower()
                content = block.get("content", "")
            
                if "purple" in bg_color and ("great work" in content.lower() or "tasks completed" in content.lower()):
                    purple_callout_found = True
                    break
    
        if not purple_callout_found:
            errors.append("[X] Purple callout with completion message not found")
        else:
            checks_passed.append("[C] Purple callout with completion message found")
    
        # 8. All checks passed
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_code_examples_go_after_sql_with_stats(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate Code Examples Go Section after SQL with stats callout.
    
    Verification:
    - Go Examples heading2 appears after Sql Examples section
    - Code block with language 'go' containing fibonacci code
    - Paragraph matching pattern 'Common go pattern for production code.'
    - Divider block
    - Yellow callout with stats icon showing accurate language and code block counts
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    # 1. Query all pages from backend
    # 2. Find 'Code Examples Repository' page
    try:
        code_examples = _find_page_by_title(final_state_backend, "Code Examples Repository")
        if not code_examples:
            errors.append("[X] Code Examples Repository page not found")
        else:
            checks_passed.append("[C] Code Examples Repository page found")
    
        code_examples_id = code_examples.get("_id")
    
        # 3. Query all blocks for the page
        page_blocks = _get_blocks_for_page(final_state_backend, code_examples_id)
    
        if not page_blocks:
            errors.append("[X] Code Examples Repository page has no blocks")
        else:
            checks_passed.append("[C] Code Examples Repository page has blocks")
    
        # Sort blocks by order
        page_blocks_sorted = sorted(page_blocks, key=lambda b: b.get("order", 0))
    
        # 4. Find 'Sql Examples' heading2
        sql_heading = None
        for block in page_blocks_sorted:
            if block.get("type") == "heading2":
                content = block.get("content", "").lower()
                if "sql" in content and "examples" in content:
                    sql_heading = block
                    break
    
        if not sql_heading:
            errors.append("[X] Sql Examples heading2 not found")
        else:
            checks_passed.append("[C] Sql Examples heading2 found")
    
        sql_order = sql_heading.get("order", 0)
    
        # 5. Find 'Go Examples' heading2
        go_heading = None
        for block in page_blocks_sorted:
            if block.get("type") == "heading2" and block.get("order", 0) > sql_order:
                content = block.get("content", "").lower()
                if "go" in content and "examples" in content:
                    go_heading = block
                    break
    
        if not go_heading:
            errors.append("[X] Go Examples heading2 not found")
        else:
            checks_passed.append("[C] Go Examples heading2 found")
    
        go_order = go_heading.get("order", 0)
    
        # 6. Find code block with language 'go' containing fibonacci
        go_code_block = None
        for block in page_blocks_sorted:
            if block.get("type") == "code" and block.get("order", 0) > go_order:
                lang = block.get("properties", {}).get("language", "").lower()
                content = block.get("content", "")
                if lang == "go" and ("fibonacci" in content or "func main" in content):
                    go_code_block = block
                    break
    
        if not go_code_block:
            errors.append("[X] Go code block with fibonacci not found")
        else:
            checks_passed.append("[C] Go code block with fibonacci found")
    
        # 7. Find paragraph matching pattern
        paragraph_found = False
        for block in page_blocks_sorted:
            if block.get("type") == "paragraph" and block.get("order", 0) > go_order:
                content = block.get("content", "").lower()
                if "common go pattern" in content and "production code" in content:
                    paragraph_found = True
                    break
    
        if not paragraph_found:
            errors.append("[X] Paragraph 'Common go pattern for production code.' not found")
        else:
            checks_passed.append("[C] Paragraph 'Common go pattern for production code.' found")
    
        # 8. Find divider after Go section
        divider_found = False
        for block in page_blocks_sorted:
            if block.get("type") == "divider" and block.get("order", 0) > go_order:
                divider_found = True
                break
    
        if not divider_found:
            errors.append("[X] Divider not found after Go Examples section")
        else:
            checks_passed.append("[C] Divider found after Go Examples section")
    
        # 9. Count all language heading2 blocks and all code blocks
        language_headings = [
            b for b in page_blocks 
            if b.get("type") == "heading2" and "examples" in b.get("content", "").lower()
        ]
        all_code_blocks = [b for b in page_blocks if b.get("type") == "code"]
    
        language_count = len(language_headings)
        code_count = len(all_code_blocks)
    
        # 10. Find yellow callout with stats
        callout_found = False
        for block in page_blocks_sorted:
            if block.get("type") == "callout":
                bg_color = block.get("properties", {}).get("backgroundColor", "").lower()
                content = block.get("content", "")
            
                if "yellow" in bg_color and "repository stats" in content.lower():
                    # Check if it mentions the counts
                    if str(language_count) in content or "programming languages" in content.lower():
                        callout_found = True
                        break
    
        if not callout_found:
            errors.append("[X] Yellow callout with repository stats not found")
        else:
            checks_passed.append("[C] Yellow callout with repository stats found")
    
        # 11. All checks passed
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_product_requirements_overview_critical_updates(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate Product Requirements Overview Critical Updates task.
    
    Verification:
    - New heading3 'Overview - Critical Updates' between Part 2 and Part 3
    - Heading has red text color property
    - Quote block with today's date
    - Numbered list with exactly 3 critical items
    - Red callout with timer icon containing timeline impact text
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    # 1. Query all pages from backend
    # 2. Find 'Comprehensive Product Requirements Document' page
    try:
        product_req_doc = _find_page_by_title(final_state_backend, "Comprehensive Product Requirements")
        if not product_req_doc:
            errors.append("[X] Comprehensive Product Requirements Document page not found")
        else:
            checks_passed.append("[C] Comprehensive Product Requirements Document page found")
    
        product_req_doc_id = product_req_doc.get("_id")
    
        # 3. Query all blocks for the page
        page_blocks = _get_blocks_for_page(final_state_backend, product_req_doc_id)
    
        if not page_blocks:
            errors.append("[X] Comprehensive Product Requirements Document page has no blocks")
        else:
            checks_passed.append("[C] Comprehensive Product Requirements Document page has blocks")
    
        # Sort blocks by order
        page_blocks_sorted = sorted(page_blocks, key=lambda b: b.get("order", 0))
    
        # 4. Find 'Overview - Part 2' heading3
        part2_heading = None
        for block in page_blocks_sorted:
            if block.get("type") == "heading3":
                content = block.get("content", "").lower()
                if "overview" in content and "part 2" in content:
                    part2_heading = block
                    break
    
        if not part2_heading:
            errors.append("[X] Overview - Part 2 heading3 not found")
        else:
            checks_passed.append("[C] Overview - Part 2 heading3 found")
    
        part2_order = part2_heading.get("order", 0)
    
        # 5. Find 'Overview - Part 3' heading3
        part3_heading = None
        for block in page_blocks_sorted:
            if block.get("type") == "heading3" and block.get("order", 0) > part2_order:
                content = block.get("content", "").lower()
                if "overview" in content and "part 3" in content:
                    part3_heading = block
                    break
    
        if not part3_heading:
            errors.append("[X] Overview - Part 3 heading3 not found")
        else:
            checks_passed.append("[C] Overview - Part 3 heading3 found")
    
        part3_order = part3_heading.get("order", 0)
    
        # 6. Find 'Overview - Critical Updates' heading3 between Part 2 and Part 3
        critical_heading = None
        for block in page_blocks_sorted:
            if block.get("type") == "heading3":
                order = block.get("order", 0)
                if part2_order < order < part3_order:
                    content = block.get("content", "").lower()
                    if "critical" in content and "updates" in content:
                        critical_heading = block
                        break
    
        if not critical_heading:
            errors.append("[X] Overview - Critical Updates heading3 not found between Part 2 and Part 3")
        else:
            checks_passed.append("[C] Overview - Critical Updates heading3 found between Part 2 and Part 3")
    
        critical_order = critical_heading.get("order", 0)
    
        # 7. Check heading has red color property (if available in properties)
        # Note: Color property validation may vary based on schema
    
        # 8. Find quote block
        quote_found = False
        for block in page_blocks_sorted:
            if block.get("type") == "quote":
                order = block.get("order", 0)
                if critical_order < order < part3_order:
                    quote_found = True
                    break
    
        if not quote_found:
            errors.append("[X] Quote block not found in Critical Updates section")
        else:
            checks_passed.append("[C] Quote block found in Critical Updates section")
    
        # 9. Find numbered list with 3 items
        numbered_lists = [
            b for b in page_blocks_sorted
            if b.get("type") == "numberedList" and critical_order < b.get("order", 0) < part3_order
        ]
    
        if len(numbered_lists) < 3:
            errors.append(f"[X] Expected at least 3 numbered list items in Critical Updates section (found: {len(numbered_lists)})")
        else:
            checks_passed.append(f"[C] Expected at least 3 numbered list items in Critical Updates section (found: {len(numbered_lists)})")
    
        # 10. Find red callout with timeline impact
        callout_found = False
        for block in page_blocks_sorted:
            if block.get("type") == "callout":
                order = block.get("order", 0)
                if critical_order < order < part3_order:
                    bg_color = block.get("properties", {}).get("backgroundColor", "").lower()
                    content = block.get("content", "").lower()
                
                    if "red" in bg_color and "timeline" in content and "impact" in content:
                        callout_found = True
                        break
    
        if not callout_found:
            errors.append("[X] Red callout with Timeline Impact not found")
        else:
            checks_passed.append("[C] Red callout with Timeline Impact found")
    
        # 11. All checks passed
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_project_guidelines_statistics(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate Project Guidelines Statistics task.
    
    Verification:
    - New section after 5th callout with heading2 'Guideline Statistics'
    - Numbered list showing counts for yellow, orange, red callouts
    - Purple callout with target icon containing critical count
    - Positioned before 6th original callout
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    # 1. Query all pages from backend
    # 2. Find 'Project Guidelines & Best Practices' page
    try:
        guidelines = _find_page_by_title(final_state_backend, "Project Guidelines")
        if not guidelines:
            errors.append("[X] Project Guidelines & Best Practices page not found")
        else:
            checks_passed.append("[C] Project Guidelines & Best Practices page found")
    
        guidelines_id = guidelines.get("_id")
    
        # 3. Query all blocks for the page
        page_blocks = _get_blocks_for_page(final_state_backend, guidelines_id)
    
        if not page_blocks:
            errors.append("[X] Project Guidelines & Best Practices page has no blocks")
        else:
            checks_passed.append("[C] Project Guidelines & Best Practices page has blocks")
    
        # Sort blocks by order
        page_blocks_sorted = sorted(page_blocks, key=lambda b: b.get("order", 0))
    
        # 4. Count callouts by background color
        callouts = [b for b in page_blocks if b.get("type") == "callout"]
    
        yellow_count = sum(1 for c in callouts if "yellow" in c.get("properties", {}).get("backgroundColor", "").lower())
        orange_count = sum(1 for c in callouts if "orange" in c.get("properties", {}).get("backgroundColor", "").lower())
        red_count = sum(1 for c in callouts if "red" in c.get("properties", {}).get("backgroundColor", "").lower())
    
        # 5. Find 'Guideline Statistics' heading2
        stats_heading = None
        for block in page_blocks_sorted:
            if block.get("type") == "heading2":
                content = block.get("content", "").lower()
                if "guideline" in content and "statistics" in content:
                    stats_heading = block
                    break
    
        if not stats_heading:
            errors.append("[X] Guideline Statistics heading2 not found")
        else:
            checks_passed.append("[C] Guideline Statistics heading2 found")
    
        stats_order = stats_heading.get("order", 0)
    
        # 6. Find numbered list after stats heading
        numbered_lists = [
            b for b in page_blocks_sorted
            if b.get("type") == "numberedList" and b.get("order", 0) > stats_order
        ]
    
        if len(numbered_lists) < 3:
            errors.append(f"[X] Expected at least 3 numbered list items for statistics (found: {len(numbered_lists)})")
        else:
            checks_passed.append(f"[C] Expected at least 3 numbered list items for statistics (found: {len(numbered_lists)})")
    
        # 7. Find purple callout
        purple_callout_found = False
        for block in page_blocks_sorted:
            if block.get("type") == "callout" and block.get("order", 0) > stats_order:
                bg_color = block.get("properties", {}).get("backgroundColor", "").lower()
                content = block.get("content", "").lower()
            
                if "purple" in bg_color and "priority" in content and "focus" in content:
                    purple_callout_found = True
                    break
    
        if not purple_callout_found:
            errors.append("[X] Purple callout with priority focus not found")
        else:
            checks_passed.append("[C] Purple callout with priority focus found")
    
        # 8. All checks passed
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_code_examples_swift_section(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate Code Examples Swift Section task completion.
    
    Verification:
    - Swift Examples heading2 appears after Rust Examples heading
    - Code block with language 'swift' containing struct User and fetchUser function
    - Paragraph following pattern 'Common swift pattern for production code.'
    - Image block with Swift icon URL and caption
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    # 1. Query all pages from backend
    # 2. Find 'Code Examples Repository' page
    try:
        code_examples = _find_page_by_title(final_state_backend, "Code Examples Repository")
        if not code_examples:
            errors.append("[X] Code Examples Repository page not found")
        else:
            checks_passed.append("[C] Code Examples Repository page found")
    
        code_examples_id = code_examples.get("_id")
    
        # 3. Query all blocks for the page
        page_blocks = _get_blocks_for_page(final_state_backend, code_examples_id)
    
        if not page_blocks:
            errors.append("[X] Code Examples Repository page has no blocks")
        else:
            checks_passed.append("[C] Code Examples Repository page has blocks")
    
        # Sort blocks by order
        page_blocks_sorted = sorted(page_blocks, key=lambda b: b.get("order", 0))
    
        # 4. Find 'Rust Examples' heading2
        rust_heading = None
        for block in page_blocks_sorted:
            if block.get("type") == "heading2":
                content = block.get("content", "").lower()
                if "rust" in content and "examples" in content:
                    rust_heading = block
                    break
    
        if not rust_heading:
            errors.append("[X] Rust Examples heading2 not found")
        else:
            checks_passed.append("[C] Rust Examples heading2 found")
    
        rust_order = rust_heading.get("order", 0)
    
        # 5. Find 'Swift Examples' heading2
        swift_heading = None
        for block in page_blocks_sorted:
            if block.get("type") == "heading2" and block.get("order", 0) > rust_order:
                content = block.get("content", "").lower()
                if "swift" in content and "examples" in content:
                    swift_heading = block
                    break
    
        if not swift_heading:
            errors.append("[X] Swift Examples heading2 not found")
        else:
            checks_passed.append("[C] Swift Examples heading2 found")
    
        swift_order = swift_heading.get("order", 0)
    
        # 6. Find code block after Swift heading with language 'swift'
        swift_code_block = None
        for block in page_blocks_sorted:
            if block.get("type") == "code" and block.get("order", 0) > swift_order:
                lang = block.get("properties", {}).get("language", "").lower()
                if lang == "swift":
                    swift_code_block = block
                    break
                # Stop searching after first non-Swift code block or major heading
                elif block.get("type") in {"heading1", "heading2"}:
                    break
    
        if not swift_code_block:
            errors.append("[X] Swift code block not found after Swift Examples heading")
        else:
            checks_passed.append("[C] Swift code block found after Swift Examples heading")
    
        # 7. Verify code block contains expected Swift code
        code_content = swift_code_block.get("content", "")
        if "struct User" not in code_content:
            errors.append("[X] Swift code block does not contain 'struct User'")
        else:
            checks_passed.append("[C] Swift code block does contains 'struct User'")
    
        if "func fetchUser" not in code_content:
            errors.append("[X] Swift code block does not contain 'func fetchUser'")
        else:
            checks_passed.append("[C] Swift code block does contains 'func fetchUser'")
    
        # 8. Find paragraph after code block
        paragraph_found = False
        for block in page_blocks_sorted:
            if block.get("type") == "paragraph" and block.get("order", 0) > swift_order:
                content = block.get("content", "").lower()
                if "common swift pattern" in content and "production code" in content:
                    paragraph_found = True
                    break
                # Stop searching after major heading
                elif block.get("type") in {"heading1", "heading2"}:
                    break
    
        if not paragraph_found:
            errors.append("[X] Paragraph 'Common swift pattern for production code.' not found")
        else:
            checks_passed.append("[C] Paragraph 'Common swift pattern for production code.' found")
    
        # 9. Find image block with Swift URL
        image_found = False
        for block in page_blocks_sorted:
            if block.get("type") == "image" and block.get("order", 0) > swift_order:
                url = block.get("properties", {}).get("url", "").lower()
                caption = block.get("properties", {}).get("caption", "").lower()
            
                if "swift" in url and ("developer.apple.com" in url or "swift" in caption):
                    image_found = True
                    break
                # Stop searching after major heading
                elif block.get("type") in {"heading1", "heading2"}:
                    break
    
        if not image_found:
            errors.append("[X] Image block with Swift icon URL not found")
        else:
            checks_passed.append("[C] Image block with Swift icon URL found")
    
        # 10. All checks passed
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_product_requirements_implementation_timeline(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate Product Requirements Implementation Timeline task completion.
    
    Verification:
    - Implementation Timeline section added after Technical Requirements Part 3
    - Divider before the new section
    - Two phases with heading3 blocks
    - Exactly 6 unchecked todo blocks (3 per phase)
    - Blue callout with correct summary statistics
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    # 1. Query all pages from backend
    # 2. Find 'Comprehensive Product Requirements Document' page
    try:
        product_req_doc = _find_page_by_title(final_state_backend, "Comprehensive Product Requirements")
        if not product_req_doc:
            errors.append("[X] Comprehensive Product Requirements Document page not found")
        else:
            checks_passed.append("[C] Comprehensive Product Requirements Document page found")
    
        product_req_doc_id = product_req_doc.get("_id")
    
        # 3. Query all blocks for the page
        page_blocks = _get_blocks_for_page(final_state_backend, product_req_doc_id)
    
        if not page_blocks:
            errors.append("[X] Comprehensive Product Requirements Document page has no blocks")
        else:
            checks_passed.append("[C] Comprehensive Product Requirements Document page has blocks")
    
        # Sort blocks by order
        page_blocks_sorted = sorted(page_blocks, key=lambda b: b.get("order", 0))
    
        # 4. Find 'Technical Requirements - Part 3' heading3
        part3_heading = None
        for block in page_blocks_sorted:
            if block.get("type") == "heading3":
                content = block.get("content", "").lower()
                if "technical requirements" in content and "part 3" in content:
                    part3_heading = block
                    break
    
        if not part3_heading:
            errors.append("[X] Technical Requirements - Part 3 heading3 not found")
        else:
            checks_passed.append("[C] Technical Requirements - Part 3 heading3 found")
    
        part3_order = part3_heading.get("order", 0)
    
        # 5. Find '📅 Implementation Timeline' heading2
        timeline_heading = None
        for block in page_blocks_sorted:
            if block.get("type") == "heading2":
                content = block.get("content", "").lower()
                if "implementation timeline" in content:
                    timeline_heading = block
                    break
    
        if not timeline_heading:
            errors.append("[X] Implementation Timeline heading2 not found")
        else:
            checks_passed.append("[C] Implementation Timeline heading2 found")
    
        timeline_order = timeline_heading.get("order", 0)
    
        # 6. Verify divider exists before timeline heading
        divider_found = False
        for block in page_blocks_sorted:
            if block.get("type") == "divider":
                divider_order = block.get("order", 0)
                # Divider should be close to timeline heading
                if timeline_order - 5 < divider_order < timeline_order:
                    divider_found = True
                    break
    
        if not divider_found:
            errors.append("[X] Divider not found before Implementation Timeline section")
        else:
            checks_passed.append("[C] Divider found before Implementation Timeline section")
    
        # 7. Find 'Phase 1: Foundation' heading3
        phase1_heading = None
        for block in page_blocks_sorted:
            if block.get("type") == "heading3" and block.get("order", 0) > timeline_order:
                content = block.get("content", "").lower()
                if "phase 1" in content and "foundation" in content:
                    phase1_heading = block
                    break
    
        if not phase1_heading:
            errors.append("[X] Phase 1: Foundation heading3 not found")
        else:
            checks_passed.append("[C] Phase 1: Foundation heading3 found")
    
        phase1_order = phase1_heading.get("order", 0)
    
        # 8. Find 'Phase 2: Core Features' heading3
        phase2_heading = None
        for block in page_blocks_sorted:
            if block.get("type") == "heading3" and block.get("order", 0) > phase1_order:
                content = block.get("content", "").lower()
                if "phase 2" in content and "core features" in content:
                    phase2_heading = block
                    break
    
        if not phase2_heading:
            errors.append("[X] Phase 2: Core Features heading3 not found")
        else:
            checks_passed.append("[C] Phase 2: Core Features heading3 found")
    
        phase2_order = phase2_heading.get("order", 0)
    
        # 9. Count todos between Phase 1 and Phase 2
        phase1_todos = [
            b for b in page_blocks_sorted
            if b.get("type") == "todo" and phase1_order < b.get("order", 0) < phase2_order
        ]
    
        if len(phase1_todos) != 3:
            errors.append(f"[X] Phase 1 should have exactly 3 todo blocks (found: {len(phase1_todos)})")
        else:
            checks_passed.append(f"[C] Phase 1 should have exactly 3 todo blocks (found: {len(phase1_todos)})")
    
        # 10. Count todos after Phase 2
        phase2_todos = [
            b for b in page_blocks_sorted
            if b.get("type") == "todo" and b.get("order", 0) > phase2_order
        ]
    
        # Check for at least 3 todos in Phase 2 (there might be more from other sections)
        # We'll count todos up to the next major heading or callout
        phase2_todos_count = 0
        for block in page_blocks_sorted:
            if block.get("order", 0) > phase2_order:
                if block.get("type") == "todo":
                    phase2_todos_count += 1
                elif block.get("type") in {"heading2", "callout"}:
                    break
    
        if phase2_todos_count < 3:
            errors.append(f"[X] Phase 2 should have at least 3 todo blocks (found: {phase2_todos_count})")
        else:
            checks_passed.append(f"[C] Phase 2 should have at least 3 todo blocks (found: {phase2_todos_count})")
    
        # 11. Verify all todos in timeline section are unchecked
        timeline_todos = phase1_todos + [
            b for b in page_blocks_sorted
            if b.get("type") == "todo" and phase2_order < b.get("order", 0) < phase2_order + 10
        ][:3]
    
        checked_todos = [t for t in timeline_todos if t.get("properties", {}).get("checked") == True]
        if checked_todos:
            errors.append(f"[X] All timeline todos should be unchecked (found {len(checked_todos)} checked)")
        else:
            checks_passed.append(f"[C] All timeline todos should be unchecked (found {len(checked_todos)} checked)")
    
        # 12. Find blue callout with statistics
        callout_found = False
        for block in page_blocks_sorted:
            if block.get("type") == "callout" and block.get("order", 0) > timeline_order:
                bg_color = block.get("properties", {}).get("backgroundColor", "").lower()
                content = block.get("content", "").lower()
            
                if "blue" in bg_color and ("implementation items" in content or "target completion" in content):
                    callout_found = True
                    # Verify it mentions "6" items and "8 weeks"
                    if "6" not in content:
                        errors.append("[X] Blue callout should mention 6 implementation items")
                    else:
                        checks_passed.append("[C] Blue callout should mention 6 implementation items")
                    if "8 weeks" not in content:
                        errors.append("[X] Blue callout should mention 8 weeks target completion")
                    else:
                        checks_passed.append("[C] Blue callout should mention 8 weeks target completion")
                    break
    
        if not callout_found:
            errors.append("[X] Blue callout with implementation statistics not found")
        else:
            checks_passed.append("[C] Blue callout with implementation statistics found")
    
        # 13. All checks passed
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_getting_started_onboarding_tracker(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate Getting Started Onboarding Tracker task completion.
    
    Verification:
    - Onboarding Progress Tracker heading2 positioned before Quick Start Checklist
    - Callout with dynamic color based on completion percentage (green/yellow/red)
    - Callout contains progress icon and formatted stats with appropriate stage
    - Toggle block with personalized next steps for unchecked todos
    - Toggle ends with divider and italic timestamp
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    # 1. Query all pages from backend
    # 2. Find 'Getting Started' page
    try:
        getting_started = _find_page_by_title(final_state_backend, "Getting Started")
        if not getting_started:
            errors.append("[X] Getting Started page not found")
        else:
            checks_passed.append("[C] Getting Started page found")
    
        getting_started_id = getting_started.get("_id")
    
        # 3. Query all blocks for Getting Started page
        page_blocks = _get_blocks_for_page(final_state_backend, getting_started_id)
    
        if not page_blocks:
            errors.append("[X] Getting Started page has no blocks")
        else:
            checks_passed.append("[C] Getting Started page has blocks")
    
        # Sort blocks by order
        page_blocks_sorted = sorted(page_blocks, key=lambda b: b.get("order", 0))
    
        # 4. Find 'Quick Start Checklist' heading
        checklist_heading = None
        for block in page_blocks_sorted:
            if block.get("type") in {"heading1", "heading2", "heading3"}:
                content = block.get("content", "").lower()
                if "quick start" in content and "checklist" in content:
                    checklist_heading = block
                    break
    
        if not checklist_heading:
            errors.append("[X] Quick Start Checklist heading not found")
        else:
            checks_passed.append("[C] Quick Start Checklist heading found")
    
        checklist_order = checklist_heading.get("order", 0)
    
        # 5. Count todos in the checklist section (todos that come after the checklist heading)
        checklist_todos = []
        for block in page_blocks_sorted:
            if block.get("order", 0) > checklist_order:
                if block.get("type") == "todo":
                    checklist_todos.append(block)
                # Stop if we hit another major heading
                elif block.get("type") in {"heading1", "heading2"}:
                    break
    
        if not checklist_todos:
            errors.append("[X] No todo blocks found in Quick Start Checklist section")
        else:
            checks_passed.append("[C] todo blocks found in Quick Start Checklist section")
    
        total_checklist_todos = len(checklist_todos)
        checked_checklist_todos = sum(1 for t in checklist_todos if t.get("properties", {}).get("checked") == True)
        completion_percentage = (checked_checklist_todos / total_checklist_todos * 100) if total_checklist_todos > 0 else 0
    
        # 6. Find '📊 Onboarding Progress Tracker' heading2
        tracker_heading = None
        for block in page_blocks_sorted:
            content = block.get("content", "").lower()
            if block.get("type") == "heading2" and "onboarding progress tracker" in content:
                tracker_heading = block
                break
    
        if not tracker_heading:
            errors.append("[X] Onboarding Progress Tracker heading2 not found")
        else:
            checks_passed.append("[C] Onboarding Progress Tracker heading2 found")
    
        tracker_order = tracker_heading.get("order", 0)
    
        # 7. Verify tracker is positioned before checklist
        if tracker_order >= checklist_order:
            errors.append(f"[X] Onboarding Progress Tracker must appear before Quick Start Checklist (tracker order: {tracker_order}, checklist order: {checklist_order})")
        else:
            checks_passed.append(f"[C] Onboarding Progress Tracker must appear before Quick Start Checklist (tracker order: {tracker_order}, checklist order: {checklist_order})")
    
        # 8. Find callout block after tracker heading
        callout_block = None
        for block in page_blocks_sorted:
            if block.get("order", 0) > tracker_order and block.get("order", 0) < checklist_order:
                if block.get("type") == "callout":
                    callout_block = block
                    break
    
        if not callout_block:
            errors.append("[X] Callout block not found after Onboarding Progress Tracker")
        else:
            checks_passed.append("[C] Callout block found after Onboarding Progress Tracker")
    
        # 9. Verify callout background color matches completion percentage
        bg_color = callout_block.get("properties", {}).get("backgroundColor", "").lower()
        expected_color = None
    
        if completion_percentage >= 50:
            expected_color = "green"
        elif completion_percentage >= 25:
            expected_color = "yellow"
        else:
            expected_color = "red"
    
        if expected_color not in bg_color:
            errors.append(f"[X] Callout background color is '{bg_color}', expected '{expected_color}' based on {completion_percentage:.0f}% completion")
        else:
            checks_passed.append(f"[C] Callout background color is '{bg_color}', expected '{expected_color}' based on {completion_percentage:.0f}% completion")
    
        # 10. Verify callout has progress icon (📈)
        callout_icon = callout_block.get("properties", {}).get("icon", "")
        if "📈" not in callout_icon:
            errors.append(f"[X] Callout does not have progress icon 📈 (found: '{callout_icon}')")
        else:
            checks_passed.append(f"[C] Callout has progress icon 📈 (found: '{callout_icon}')")
    
        # 11. Verify callout text contains required elements
        callout_content = callout_block.get("content", "").lower()
    
        if "current progress" not in callout_content:
            errors.append("[X] Callout missing 'Current Progress' text")
        else:
            checks_passed.append("[C] Callout has 'Current Progress' text")
    
        if "status:" not in callout_content:
            errors.append("[X] Callout missing 'Status:' text")
        else:
            checks_passed.append("[C] Callout has 'Status:' text")
    
        # Check for appropriate stage text based on completion
        stage_found = False
        if completion_percentage < 25 and "getting started" in callout_content:
            stage_found = True
        elif 25 <= completion_percentage < 50 and "making progress" in callout_content:
            stage_found = True
        elif 50 <= completion_percentage < 100 and "almost there" in callout_content:
            stage_found = True
        elif completion_percentage == 100 and "fully onboarded" in callout_content:
            stage_found = True
    
        if not stage_found:
            errors.append(f"[X] Callout stage text incorrect for {completion_percentage:.0f}% completion")
        else:
            checks_passed.append(f"[C] Callout stage text incorrect for {completion_percentage:.0f}% completion")
    
        # 12. Find toggle block '🎯 Personalized Next Steps'
        toggle_block = None
        for block in page_blocks_sorted:
            if block.get("order", 0) > tracker_order and block.get("order", 0) < checklist_order:
                if block.get("type") == "toggle":
                    content = block.get("content", "").lower()
                    if "personalized" in content and "next steps" in content:
                        toggle_block = block
                        break
    
        if not toggle_block:
            errors.append("[X] Toggle block 'Personalized Next Steps' not found")
        else:
            checks_passed.append("[C] Toggle block 'Personalized Next Steps' found")
    
        # 13. Verify toggle contains numbered list (check for numberedList blocks after toggle)
        # Note: In the actual structure, we'd need to check for child blocks or subsequent blocks
        # For this validation, we check if numbered lists exist in the section
        numbered_lists_in_section = [
            b for b in page_blocks_sorted 
            if b.get("type") == "numberedList" and tracker_order < b.get("order", 0) < checklist_order
        ]
    
        if not numbered_lists_in_section:
            errors.append("[X] No numbered list found in toggle block area")
        else:
            checks_passed.append("[C] numbered list found in toggle block area")
    
        # 14. Verify divider exists in the section
        dividers_in_section = [
            b for b in page_blocks_sorted 
            if b.get("type") == "divider" and tracker_order < b.get("order", 0) < checklist_order
        ]
    
        if not dividers_in_section:
            errors.append("[X] Divider not found in toggle block area")
        else:
            checks_passed.append("[C] Divider found in toggle block area")
    
        # 15. All checks passed
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_feature_requests_priority_matrix(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate Feature Requests Priority Matrix task completion.
    
    Verification:
    - Feature Priority Matrix heading_1 at top of page
    - High Priority heading_2 with numbered list of unchecked todos
    - Completed Features heading_2 with numbered list of checked todos
    - Completion Summary heading_2 with blue callout showing statistics
    - Toggle block with date information
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    # 1. Query all pages from backend
    # 2. Find 'Feature Requests' page
    try:
        feature_requests = _find_page_by_title(final_state_backend, "Feature Requests")
        if not feature_requests:
            errors.append("[X] Feature Requests page not found")
        else:
            checks_passed.append("[C] Feature Requests page found")
    
        feature_requests_id = feature_requests.get("_id")
    
        # 3. Query all blocks for Feature Requests page
        page_blocks = _get_blocks_for_page(final_state_backend, feature_requests_id)
    
        if not page_blocks:
            errors.append("[X] Feature Requests page has no blocks")
        else:
            checks_passed.append("[C] Feature Requests page has blocks")
    
        # Sort blocks by order to check positioning
        page_blocks_sorted = sorted(page_blocks, key=lambda b: b.get("order", 0))
    
        # 4. Find '🎯 Feature Priority Matrix' heading_1
        priority_matrix_heading = None
        for block in page_blocks_sorted:
            if block.get("type") == "heading1" and "feature priority matrix" in block.get("content", "").lower():
                priority_matrix_heading = block
                break
    
        if not priority_matrix_heading:
            errors.append("[X] Feature Priority Matrix heading_1 not found")
        else:
            checks_passed.append("[C] Feature Priority Matrix heading_1 found")
    
        # 5. Check if it's at the top (should be one of the first blocks)
        matrix_order = priority_matrix_heading.get("order", float('inf'))
        if matrix_order > 5:
            errors.append(f"[X] Feature Priority Matrix is not at top of page (order: {matrix_order})")
        else:
            checks_passed.append(f"[C] Feature Priority Matrix is at top of page (order: {matrix_order})")
    
        # 6. Count all todo blocks on the page
        all_todos = [b for b in page_blocks if b.get("type") == "todo"]
        checked_todos = [t for t in all_todos if t.get("properties", {}).get("checked") == True]
        unchecked_todos = [t for t in all_todos if not t.get("properties", {}).get("checked")]
    
        total_todos = len(all_todos)
        checked_count = len(checked_todos)
        unchecked_count = len(unchecked_todos)
    
        if total_todos == 0:
            errors.append("[X] No todo blocks found on Feature Requests page")
        else:
            checks_passed.append("[C] todo blocks found on Feature Requests page")
    
        # 7. Find '🔴 High Priority (Unchecked Items)' heading_2
        high_priority_heading = None
        for block in page_blocks_sorted:
            content = block.get("content", "").lower()
            if block.get("type") == "heading2" and "high priority" in content and "unchecked" in content:
                high_priority_heading = block
                break
    
        if not high_priority_heading:
            errors.append("[X] High Priority (Unchecked Items) heading_2 not found")
        else:
            checks_passed.append("[C] High Priority (Unchecked Items) heading_2 found")
    
        # 8. Count numbered list blocks (should match unchecked todo count)
        numbered_lists = [b for b in page_blocks if b.get("type") == "numberedList"]
        # Note: We can't strictly validate the count matches perfectly without more context,
        # but we can check that numbered lists exist
        if not numbered_lists:
            errors.append("[X] No numbered list blocks found for categorized todos")
        else:
            checks_passed.append("[C] numbered list blocks found for categorized todos")
    
        # 9. Find '🟢 Completed Features' heading_2
        completed_heading = None
        for block in page_blocks_sorted:
            content = block.get("content", "").lower()
            if block.get("type") == "heading2" and "completed" in content and "feature" in content:
                completed_heading = block
                break
    
        if not completed_heading:
            errors.append("[X] Completed Features heading_2 not found")
        else:
            checks_passed.append("[C] Completed Features heading_2 found")
    
        # 10. Find '📊 Completion Summary' heading_2
        summary_heading = None
        for block in page_blocks_sorted:
            content = block.get("content", "").lower()
            if block.get("type") == "heading2" and "completion" in content and "summary" in content:
                summary_heading = block
                break
    
        if not summary_heading:
            errors.append("[X] Completion Summary heading_2 not found")
        else:
            checks_passed.append("[C] Completion Summary heading_2 found")
    
        # 11. Find blue callout with statistics
        callout_blocks = [b for b in page_blocks if b.get("type") == "callout"]
        blue_callout_found = False
        callout_has_stats = False
    
        for callout in callout_blocks:
            bg_color = callout.get("properties", {}).get("backgroundColor")
            content = callout.get("content", "").lower()
        
            if bg_color and "blue" in bg_color:
                blue_callout_found = True
                # Check if it contains statistics-like content
                if "total" in content or "implementation" in content or "%" in content:
                    callout_has_stats = True
                    break
    
        if not blue_callout_found:
            errors.append("[X] Blue callout block not found")
        else:
            checks_passed.append("[C] Blue callout block found")
    
        if not callout_has_stats:
            errors.append("[X] Blue callout does not contain statistics")
        else:
            checks_passed.append("[C] Blue callout does contains statistics")
    
        # 12. Find toggle block
        toggle_blocks = [b for b in page_blocks if b.get("type") == "toggle"]
        if not toggle_blocks:
            errors.append("[X] Toggle block not found")
        else:
            checks_passed.append("[C] Toggle block found")
    
        # Check if any toggle contains date-related content
        toggle_has_date = False
        for toggle in toggle_blocks:
            content = toggle.get("content", "").lower()
            if "view" in content and "metric" in content:
                toggle_has_date = True
                break
    
        if not toggle_has_date:
            errors.append("[X] Toggle block 'View detailed metrics' not found")
        else:
            checks_passed.append("[C] Toggle block 'View detailed metrics' found")
    
        # 13. All checks passed
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_project_task_analysis_creation(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate Project Task Analysis page creation.
    
    Verification:
    - New page '📊 Project Task Analysis' exists as child of 'Project Documentation'
    - Page contains analysis of all sub-pages in the Project Documentation hierarchy
    - Each analyzed page has heading_2 with '📁 ' prefix
    - Three bulleted list items per page showing block count, most common type, and last updated
    - All data is accurate
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    # 1. Find page with exact title '📊 Project Task Analysis'
    try:
        analysis_page = _find_page_by_title(final_state_backend, "📊 Project Task Analysis")
        if not analysis_page:
            errors.append("[X] Page '📊 Project Task Analysis' not found")
        else:
            checks_passed.append("[C] Page '📊 Project Task Analysis' found")

        analysis_page_id = analysis_page.get("_id")

        # 2. Verify page is child of 'Project Documentation'
        parent_id = analysis_page.get("parentId")
        if not parent_id:
            errors.append("[X] Page '📊 Project Task Analysis' has no parent")
        else:
            checks_passed.append("[C] Page '📊 Project Task Analysis' has parent")

        parent_page = _find_page_by_id(final_state_backend, parent_id)
        if not parent_page:
            errors.append(f"[X] Parent page with id '{parent_id}' not found")
        else:
            checks_passed.append(f"[C] Parent page with id '{parent_id}' found")

        parent_title = parent_page.get("title", "")
        if parent_title != "Project Documentation":
            errors.append(f"[X] Page is not a child of 'Project Documentation' (parent: '{parent_title}')")
        else:
            checks_passed.append(f"[C] Page is a child of 'Project Documentation' (parent: '{parent_title}')")

        # 3. Build Project Documentation hierarchy using query-level filtering
        project_doc_id = parent_page.get("_id")
        descendant_pages = _get_all_descendant_pages_from_backend(final_state_backend, project_doc_id)
    
        # 5. Get all blocks from backend
    
        # 6. Filter to only pages that have at least one block
        # Exclude the analysis page itself (it can't analyze itself)
        pages_with_blocks = []
        for page in descendant_pages:
            page_id = page.get("_id")
            if page_id == analysis_page_id:  # Skip the analysis page itself
                continue
            page_blocks = _get_blocks_for_page(final_state_backend, page_id)
            if page_blocks:
                pages_with_blocks.append(page)
    
        if not pages_with_blocks:
            errors.append("[X] No pages with blocks found under Project Documentation")
        else:
            checks_passed.append("[C] pages with blocks found under Project Documentation")
    
        # 7. Get blocks for the analysis page
        analysis_blocks = _get_blocks_for_page(final_state_backend, analysis_page_id)
        if not analysis_blocks:
            errors.append("[X] Analysis page has no blocks")
        else:
            checks_passed.append("[C] Analysis page has blocks")
    
        # Sort blocks by order
        analysis_blocks_sorted = sorted(analysis_blocks, key=lambda b: b.get("order", 0))
    
        # 8. Find all heading_2 blocks
        heading2_blocks = [b for b in analysis_blocks_sorted if b.get("type") == "heading2"]
    
        if not heading2_blocks:
            errors.append("[X] No heading_2 blocks found on analysis page")
        else:
            checks_passed.append("[C] heading_2 blocks found on analysis page")
    
        # 9. Verify each page with blocks has a corresponding heading_2
        documented_pages = {}  # Maps page_id to (heading_block, bullet_blocks)
    
        for heading in heading2_blocks:
            content = heading.get("content", "")
        
            # Check if heading starts with '📁 '
            if not content.startswith("📁 "):
                continue
        
            # Extract page title from heading (remove '📁 ' prefix)
            heading_title = content[2:].strip()
        
            # Find matching page (case-insensitive)
            matching_page = None
            for page in pages_with_blocks:
                if page.get("title", "").lower() == heading_title.lower():
                    matching_page = page
                    break
        
            if matching_page:
                page_id = matching_page.get("_id")
            
                # Find the next 3 blocks after this heading
                heading_index = analysis_blocks_sorted.index(heading)
                next_blocks = analysis_blocks_sorted[heading_index + 1:heading_index + 4]
            
                documented_pages[page_id] = (heading, next_blocks, matching_page)
    
        # 10. Verify all pages with blocks are documented
        for page in pages_with_blocks:
            page_id = page.get("_id")
            if page_id not in documented_pages:
                errors.append(f"[X] Missing heading for page '{page.get('title')}'")
            else:
                checks_passed.append(f"[C] has heading for page '{page.get('title')}'")
    
        # 11. Verify bullet structure and data accuracy for each documented page
        for page_id, (heading, bullet_blocks, page) in documented_pages.items():
            page_title = page.get("title", "")
        
            # Check we have exactly 3 blocks
            if len(bullet_blocks) < 3:
                errors.append(f"[X] Missing bullet items for page '{page_title}' (found {len(bullet_blocks)}, expected 3)")
            else:
                checks_passed.append(f"[C] has bullet items for page '{page_title}' (found {len(bullet_blocks)}, expected 3)")
        
            # Check all 3 are bulletedList type
            for i, block in enumerate(bullet_blocks[:3]):
                if block.get("type") != "bulletedList":
                    errors.append(f"[X] Block after heading for '{page_title}' is not bulletedList (position {i+1})")
                else:
                    checks_passed.append(f"[C] Block after heading for '{page_title}' is bulletedList (position {i+1})")
        
            # Extract bullet contents
            bullet1_content = bullet_blocks[0].get("content", "")
            bullet2_content = bullet_blocks[1].get("content", "")
            bullet3_content = bullet_blocks[2].get("content", "")
        
            # Verify bullet 1: Block count
            if not bullet1_content.lower().startswith("• block count:"):
                errors.append(f"[X] First bullet for '{page_title}' does not start with '• Block count:'")
            else:
                checks_passed.append(f"[C] First bullet for '{page_title}' start with '• Block count:'")
        
            stated_count = _extract_number_from_bullet(bullet1_content)
            if stated_count is None:
                errors.append(f"[X] Could not extract block count from bullet for '{page_title}'")
            else:
                checks_passed.append(f"[C] Could extract block count from bullet for '{page_title}'")
        
            # Calculate actual block count
            actual_blocks = _get_blocks_for_page(final_state_backend, page_id)
            actual_count = len(actual_blocks)
        
            if stated_count != actual_count:
                errors.append(f"[X] Incorrect block count for '{page_title}': stated {stated_count}, actual {actual_count}")
            else:
                checks_passed.append(f"[C] Incorrect block count for '{page_title}': stated {stated_count}, actual {actual_count}")
        
            # Verify bullet 2: Most common block type
            if not bullet2_content.lower().startswith("• most common block type:"):
                errors.append(f"[X] Second bullet for '{page_title}' does not start with '• Most common block type:'")
            else:
                checks_passed.append(f"[C] Second bullet for '{page_title}' start with '• Most common block type:'")
        
            stated_type = _extract_type_from_bullet(bullet2_content)
            if stated_type is None:
                errors.append(f"[X] Could not extract block type from bullet for '{page_title}'")
            else:
                checks_passed.append(f"[C] Could extract block type from bullet for '{page_title}'")
        
            # Calculate actual most common type
            actual_type = _get_most_common_block_type(actual_blocks)
        
            # For ties, we need to check if stated_type is among the tied types
            from collections import Counter
            type_counts = Counter(b.get("type") for b in actual_blocks if b.get("type"))
            max_count = max(type_counts.values()) if type_counts else 0
            tied_types = [t for t, c in type_counts.items() if c == max_count]
        
            if stated_type not in tied_types:
                errors.append(f"[X] Incorrect most common block type for '{page_title}': stated '{stated_type}', expected one of {tied_types}")
            else:
                checks_passed.append(f"[C] Incorrect most common block type for '{page_title}': stated '{stated_type}', expected one of {tied_types}")
        
            # Verify bullet 3: Last updated date
            if not bullet3_content.lower().startswith("• last updated:"):
                errors.append(f"[X] Third bullet for '{page_title}' does not start with '• Last updated:'")
            else:
                checks_passed.append(f"[C] Third bullet for '{page_title}' start with '• Last updated:'")
        
            stated_date = _extract_date_from_bullet(bullet3_content)
            if stated_date is None:
                errors.append(f"[X] Could not extract date from bullet for '{page_title}' or date not in YYYY-MM-DD format")
            else:
                checks_passed.append(f"[C] Could extract date from bullet for '{page_title}' or date in YYYY-MM-DD format")
        
            # Get actual date from page
            updated_at = page.get("updatedAt")
            if not updated_at:
                errors.append(f"[X] Page '{page_title}' has no updatedAt field")
            else:
                checks_passed.append(f"[C] Page '{page_title}' has updatedAt field")
        
            actual_date = _format_date_from_iso(updated_at)
            if actual_date is None:
                errors.append(f"[X] Could not parse updatedAt for '{page_title}'")
            else:
                checks_passed.append(f"[C] Could parse updatedAt for '{page_title}'")
        
            if stated_date != actual_date:
                errors.append(f"[X] Incorrect date for '{page_title}': stated '{stated_date}', actual '{actual_date}'")
            else:
                checks_passed.append(f"[C] Incorrect date for '{page_title}': stated '{stated_date}', actual '{actual_date}'")
    
        # 12. All checks passed
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_learning_path_navigator_creation(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate Learning Path Navigator page creation.
    
    Verification:
    - New page '🎓 Learning Path Navigator' exists as child of 'Onboarding Guide'
    - Page contains analysis of all pages with code blocks
    - Structured with heading1, heading2 for Technical Resources
    - Each page with code blocks has heading3 with icon and title
    - Numbered lists show language counts per page
    - Learning Checklist section with todos for each language (total counts)
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    # 1. Find page with exact title '🎓 Learning Path Navigator'
    try:
        navigator_page = _find_page_by_title(final_state_backend, "🎓 Learning Path Navigator")
        if not navigator_page:
            errors.append("[X] Page '🎓 Learning Path Navigator' not found")
        else:
            checks_passed.append("[C] Page '🎓 Learning Path Navigator' found")

        navigator_page_id = navigator_page.get("_id")

        # 2. Verify page is child of 'Onboarding Guide'
        parent_id = navigator_page.get("parentId")
        if not parent_id:
            errors.append("[X] Page '🎓 Learning Path Navigator' has no parent")
        else:
            checks_passed.append("[C] Page '🎓 Learning Path Navigator' has parent")

        onboarding_guide = _find_page_by_id(final_state_backend, parent_id)
        if not onboarding_guide or "onboarding guide" not in onboarding_guide.get("title", "").lower():
            errors.append(f"[X] Page is not a child of 'Onboarding Guide'")
        else:
            checks_passed.append(f"[C] Page is a child of 'Onboarding Guide'")

        # 3. Identify all pages with code blocks using query-level filtering
        code_blocks_by_page = _get_code_blocks_by_page_from_backend(final_state_backend)
    
        if not code_blocks_by_page:
            errors.append("[X] No pages with code blocks found")
        else:
            checks_passed.append("[C] pages with code blocks found")
    
        # 5. Get blocks for navigator page
        navigator_blocks = _get_blocks_for_page(final_state_backend, navigator_page_id)
        if not navigator_blocks:
            errors.append("[X] Navigator page has no blocks")
        else:
            checks_passed.append("[C] Navigator page has blocks")
    
        nav_blocks_sorted = sorted(navigator_blocks, key=lambda b: b.get("order", 0))
    
        # 6. Verify main structure
        if len(nav_blocks_sorted) < 2:
            errors.append("[X] Navigator page has insufficient blocks")
        else:
            checks_passed.append("[C] Navigator page has insufficient blocks")
    
        if nav_blocks_sorted[0].get("type") != "heading1" or nav_blocks_sorted[0].get("content") != "🎓 Learning Path Navigator":
            errors.append("[X] First block is not heading_1 with '🎓 Learning Path Navigator'")
        else:
            checks_passed.append("[C] First block is heading_1 with '🎓 Learning Path Navigator'")
    
        if nav_blocks_sorted[1].get("type") != "heading2" or nav_blocks_sorted[1].get("content") != "💻 Technical Resources":
            errors.append("[X] Second block is not heading_2 with '💻 Technical Resources'")
        else:
            checks_passed.append("[C] Second block is heading_2 with '💻 Technical Resources'")
    
        # 7. Find all heading_3 blocks (technical resources sections)
        heading3_blocks = [b for b in nav_blocks_sorted if b.get("type") == "heading3"]
    
        # 8. Verify each page with code blocks has a corresponding heading_3
        documented_pages = {}
    
        for heading3 in heading3_blocks:
            content = heading3.get("content", "")
            extracted = _extract_icon_and_title_from_heading(content)
        
            if not extracted:
                continue
        
            icon, title = extracted
        
            # Find matching page
            for page_id, page_code_blocks in code_blocks_by_page.items():
                page = _find_page_by_id(final_state_backend, page_id)
                if page and page.get("title", "").lower() == title.lower():
                    documented_pages[page_id] = (heading3, page)
                    break
    
        # Verify all pages with code blocks are documented
        if len(documented_pages) != len(code_blocks_by_page):
            missing_pages = set(code_blocks_by_page.keys()) - set(documented_pages.keys())
            missing_titles = [_find_page_by_id(final_state_backend, pid).get("title", pid) for pid in missing_pages]
            errors.append(f"[X] Missing heading_3 for pages with code blocks: {missing_titles}")
        else:
            checks_passed.append(f"[C] has heading_3 for pages with code blocks: {missing_titles}")
    
        # 9. Verify language counts per page
        for page_id, (heading3, page) in documented_pages.items():
            page_code_blocks = code_blocks_by_page[page_id]
            actual_lang_counts = _count_languages_on_page(page_code_blocks)
        
            # Get numbered lists following this heading3
            heading3_index = nav_blocks_sorted.index(heading3)
            numbered_lists = []
            for block in nav_blocks_sorted[heading3_index + 1:]:
                if block.get("type") == "numberedList":
                    numbered_lists.append(block)
                elif block.get("type") in ["heading1", "heading2", "heading3"]:
                    break
        
            if not numbered_lists:
                errors.append(f"[X] No numbered lists found for page '{page.get('title')}'")
            else:
                checks_passed.append(f"[C] numbered lists found for page '{page.get('title')}'")
        
            # Parse and verify language counts
            stated_lang_counts = {}
            for num_list in numbered_lists:
                content = num_list.get("content", "")
                parsed = _parse_language_count_from_numbered_list(content)
                if parsed:
                    lang, count = parsed
                    stated_lang_counts[lang] = count
        
            # Normalize and compare
            actual_normalized = {k.lower(): v for k, v in actual_lang_counts.items()}
        
            for lang, count in stated_lang_counts.items():
                if lang not in actual_normalized:
                    errors.append(f"[X] Language '{lang}' listed for '{page.get('title')}' but no code blocks found")
                else:
                    checks_passed.append(f"[C] Language '{lang}' listed for '{page.get('title')}' but code blocks found")
                if actual_normalized[lang] != count:
                    errors.append(f"[X] Incorrect count for '{lang}' on '{page.get('title')}': stated {count}, actual {actual_normalized[lang]}")
                else:
                    checks_passed.append(f"[C] Incorrect count for '{lang}' on '{page.get('title')}': stated {count}, actual {actual_normalized[lang]}")
        
            # Verify all actual languages are represented
            for lang in actual_normalized:
                if lang not in stated_lang_counts:
                    errors.append(f"[X] Missing language '{lang}' in numbered list for '{page.get('title')}'")
                else:
                    checks_passed.append(f"[C] has language '{lang}' in numbered list for '{page.get('title')}'")
    
        # 10. Find Learning Checklist section
        checklist_heading = None
        for block in nav_blocks_sorted:
            if block.get("type") == "heading2" and "learning checklist" in block.get("content", "").lower():
                checklist_heading = block
                break
    
        if not checklist_heading:
            errors.append("[X] Learning Checklist heading_2 not found")
        else:
            checks_passed.append("[C] Learning Checklist heading_2 found")
    
        # Verify checklist appears after all heading3 sections
        checklist_index = nav_blocks_sorted.index(checklist_heading)
        last_heading3_index = max([nav_blocks_sorted.index(h3) for h3, _ in documented_pages.values()])
    
        if checklist_index < last_heading3_index:
            errors.append("[X] Learning Checklist appears before all technical resource sections")
        else:
            checks_passed.append("[C] Learning Checklist appears before all technical resource sections")
    
        # 11. Calculate total language counts across all pages
        total_lang_counts = {}
        for page_code_blocks in code_blocks_by_page.values():
            lang_counts = _count_languages_on_page(page_code_blocks)
            for lang, count in lang_counts.items():
                lang_normalized = lang.lower()
                total_lang_counts[lang_normalized] = total_lang_counts.get(lang_normalized, 0) + count
    
        # 12. Verify checklist todos
        todo_blocks = [b for b in nav_blocks_sorted[checklist_index + 1:] 
                       if b.get("type") == "todo"]
    
        if not todo_blocks:
            errors.append("[X] No todo blocks found in Learning Checklist")
        else:
            checks_passed.append("[C] todo blocks found in Learning Checklist")
    
        stated_todo_langs = {}
        for todo in todo_blocks:
            content = todo.get("content", "")
            parsed = _parse_language_count_from_todo(content)
        
            if parsed:
                lang, count = parsed
                stated_todo_langs[lang] = count
            
                # Verify todo is unchecked
                if todo.get("properties", {}).get("checked"):
                    errors.append(f"[X] Todo for '{lang}' is checked (should be unchecked)")
                else:
                    checks_passed.append(f"[C] Todo for '{lang}' is checked (should be unchecked)")
    
        # Verify all languages are in checklist
        for lang, total_count in total_lang_counts.items():
            if lang not in stated_todo_langs:
                errors.append(f"[X] Missing todo for language '{lang}' in checklist")
            else:
                checks_passed.append(f"[C] has todo for language '{lang}' in checklist")
            if stated_todo_langs[lang] != total_count:
                errors.append(f"[X] Incorrect total count for '{lang}' in checklist: stated {stated_todo_langs[lang]}, actual {total_count}")
            else:
                checks_passed.append(f"[C] Incorrect total count for '{lang}' in checklist: stated {stated_todo_langs[lang]}, actual {total_count}")
    
        # Verify no extra languages in checklist
        for lang in stated_todo_langs:
            if lang not in total_lang_counts:
                errors.append(f"[X] Language '{lang}' in checklist but no code blocks found")
            else:
                checks_passed.append(f"[C] Language '{lang}' in checklist but code blocks found")
    
        # 13. All checks passed
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_q1_goals_enhancement(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate Q1 Goals page enhancement with goal tracking.
    
    Verification:
    - Callout appears after 'Key Results' heading with green background
    - Python code block with exact code
    - Sprint Velocity Tracking heading after last bulletedList
    - Three unchecked todos with specific text
    - Divider and quote at the end
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    # Find Q1 Goals page
    try:
        q1_page = _find_page_by_title(final_state_backend, "Q1 Goals")
        if not q1_page:
            errors.append("[X] Q1 Goals page not found")
        else:
            checks_passed.append("[C] Q1 Goals page found")
    
        q1_page_id = q1_page.get("_id")
    
        # Get all blocks for Q1 Goals page
        page_blocks = _get_blocks_for_page(final_state_backend, q1_page_id)
        page_blocks_sorted = sorted(page_blocks, key=lambda b: b.get("order", 0))
    
        # Find Key Results heading
        key_results_heading = None
        for block in page_blocks_sorted:
            if block.get("type") == "heading2" and "key results" in block.get("content", "").lower():
                key_results_heading = block
                break
    
        if not key_results_heading:
            errors.append("[X] Key Results heading_2 not found")
        else:
            checks_passed.append("[C] Key Results heading_2 found")
    
        key_results_index = page_blocks_sorted.index(key_results_heading)
    
        # Verify callout appears after Key Results but before first bulletedList
        callout_found = False
        code_found = False
    
        # Check blocks after Key Results heading
        next_blocks = page_blocks_sorted[key_results_index + 1:]
    
        # First should be callout
        if next_blocks and next_blocks[0].get("type") == "callout":
            callout = next_blocks[0]
            if callout.get("properties", {}).get("backgroundColor", "").lower() == "green":
                if callout.get("properties", {}).get("icon") == "🎯" and "Q1 Performance: Exceeding expectations!" in callout.get("content", ""):
                    callout_found = True
    
        if not callout_found:
            errors.append("[X] Green callout with target icon not found after Key Results heading")
        else:
            checks_passed.append("[C] Green callout with target icon found after Key Results heading")
    
        # Next should be code block with Python
        if len(next_blocks) > 1 and next_blocks[1].get("type") == "code":
            code_block = next_blocks[1]
            if code_block.get("properties", {}).get("language") == "python":
                content = code_block.get("content", "")
                required_lines = ["objectives = 3", "completed = 2", "in_progress = 1", 
                                 "success_rate = (completed/objectives) * 100", 
                                 'print(f"Q1 Success Rate: {success_rate:.1f}%")']
                if all(line in content for line in required_lines):
                    code_found = True
    
        if not code_found:
            errors.append("[X] Python code block with exact code not found after callout")
        else:
            checks_passed.append("[C] Python code block with exact code found after callout")
    
        # Find last bulletedList item
        bulleted_lists = [b for b in page_blocks_sorted if b.get("type") == "bulletedList"]
        if not bulleted_lists:
            errors.append("[X] No bulletedList items found")
        else:
            checks_passed.append("[C] bulletedList items found")
    
        last_bullet_index = page_blocks_sorted.index(bulleted_lists[-1])
    
        # Verify Sprint Velocity Tracking heading after last bullet
        velocity_heading = None
        if last_bullet_index + 1 < len(page_blocks_sorted):
            next_block = page_blocks_sorted[last_bullet_index + 1]
            if next_block.get("type") == "heading2" and "sprint velocity tracking" in next_block.get("content", "").lower():
                velocity_heading = next_block
    
        if not velocity_heading:
            errors.append("[X] Sprint Velocity Tracking heading_2 not found after last bulletedList")
        else:
            checks_passed.append("[C] Sprint Velocity Tracking heading_2 found after last bulletedList")
    
        velocity_index = page_blocks_sorted.index(velocity_heading)
    
        # Verify three todos after velocity heading
        expected_todos = [
            "📊 Update velocity charts",
            "📈 Calculate team capacity",
            "🎯 Adjust Q2 targets based on Q1 performance"
        ]
    
        todos_after_velocity = []
        for block in page_blocks_sorted[velocity_index + 1:]:
            if block.get("type") == "todo":
                todos_after_velocity.append(block)
            elif block.get("type") in ["heading1", "heading2", "heading3", "divider"]:
                break
            if len(todos_after_velocity) >= 3:
                break
    
        if len(todos_after_velocity) < 3:
            errors.append(f"[X] Expected 3 todo items after Sprint Velocity heading, found {len(todos_after_velocity)}")
        else:
            checks_passed.append(f"[C] Found 3 todo items after Sprint Velocity heading as expected")
    
        for i, expected_text in enumerate(expected_todos):
            if todos_after_velocity[i].get("content") != expected_text:
                errors.append(f"[X] Todo {i+1} text mismatch: expected '{expected_text}', got '{todos_after_velocity[i].get('content')}'")
            else:
                checks_passed.append(f"[C] Todo {i+1} text mismatch: expected '{expected_text}', got '{todos_after_velocity[i].get('content')}'")
            if todos_after_velocity[i].get("properties", {}).get("checked"):
                errors.append(f"[X] Todo {i+1} is checked (should be unchecked)")
            else:
                checks_passed.append(f"[C] Todo {i+1} is checked (should be unchecked)")
    
        # Find divider after todos
        divider_found = False
        quote_found = False
    
        remaining_blocks = page_blocks_sorted[velocity_index + 4:]  # After heading + 3 todos
    
        for i, block in enumerate(remaining_blocks):
            if block.get("type") == "divider":
                divider_found = True
                # Check for quote after divider
                if i + 1 < len(remaining_blocks):
                    next_block = remaining_blocks[i + 1]
                    if next_block.get("type") == "quote":
                        if "Excellence is not a skill, it's an attitude." in next_block.get("content", ""):
                            quote_found = True
                break
    
        if not divider_found:
            errors.append("[X] Divider not found after todos")
        else:
            checks_passed.append("[C] Divider found after todos")
    
        if not quote_found:
            errors.append("[X] Quote with exact text not found after divider")
        else:
            checks_passed.append("[C] Quote with exact text found after divider")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_feature_requests_in_progress_section(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate Feature Requests In Progress section insertion.
    
    Verification:
    - New heading_2 '🔄 In Progress' after High Priority section
    - Yellow callout with construction icon
    - Three todos in exact order with correct checked states
    - Divider after todos
    - Community Suggestions section remains intact
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    # Find Feature Requests page
    try:
        fr_page = _find_page_by_title(final_state_backend, "Feature Requests")
        if not fr_page:
            errors.append("[X] Feature Requests page not found")
        else:
            checks_passed.append("[C] Feature Requests page found")
    
        fr_page_id = fr_page.get("_id")
    
        # Get all blocks
        page_blocks = _get_blocks_for_page(final_state_backend, fr_page_id)
        page_blocks_sorted = sorted(page_blocks, key=lambda b: b.get("order", 0))
    
        # Find High Priority heading
        high_priority_heading = None
        for block in page_blocks_sorted:
            if block.get("type") == "heading2" and "high priority" in block.get("content", "").lower():
                high_priority_heading = block
                break
    
        if not high_priority_heading:
            errors.append("[X] High Priority heading_2 not found")
        else:
            checks_passed.append("[C] High Priority heading_2 found")
    
        # Find Community Suggestions heading
        community_heading = None
        for block in page_blocks_sorted:
            if block.get("type") == "heading2" and "community suggestions" in block.get("content", "").lower():
                community_heading = block
                break
    
        if not community_heading:
            errors.append("[X] Community Suggestions heading_2 not found")
        else:
            checks_passed.append("[C] Community Suggestions heading_2 found")
    
        # Find In Progress heading
        in_progress_heading = None
        for block in page_blocks_sorted:
            if block.get("type") == "heading2" and block.get("content") == "🔄 In Progress":
                in_progress_heading = block
                break
    
        if not in_progress_heading:
            errors.append("[X] In Progress heading_2 not found")
        else:
            checks_passed.append("[C] In Progress heading_2 found")
    
        # Verify In Progress appears between High Priority and Community Suggestions
        high_index = page_blocks_sorted.index(high_priority_heading)
        in_progress_index = page_blocks_sorted.index(in_progress_heading)
        community_index = page_blocks_sorted.index(community_heading)
    
        if not (high_index < in_progress_index < community_index):
            errors.append("[X] In Progress section not positioned between High Priority and Community Suggestions")
        else:
            checks_passed.append("[C] In Progress section positioned between High Priority and Community Suggestions")
    
        # Verify yellow callout after In Progress heading
        callout_found = False
        next_after_heading = page_blocks_sorted[in_progress_index + 1]
    
        if next_after_heading.get("type") == "callout":
            bg = next_after_heading.get("properties", {}).get("backgroundColor", "").lower()
            content = next_after_heading.get("content", "")
            if "yellow" in bg and block.get("properties", {}).get("icon") == "🚧":
                if "Features currently under development - expected completion Q2 2024" in content:
                    callout_found = True
    
        if not callout_found:
            errors.append("[X] Yellow callout with 🚧 icon and exact text not found")
        else:
            checks_passed.append("[C] Yellow callout with 🚧 icon and exact text found")
    
        # Find todos after callout
        todos_section = []
        for block in page_blocks_sorted[in_progress_index + 2:]:
            if block.get("type") == "todo":
                todos_section.append(block)
            elif block.get("type") in ["heading1", "heading2", "heading3", "divider"]:
                break
            if len(todos_section) >= 3:
                break
    
        if len(todos_section) != 3:
            errors.append(f"[X] Expected 3 todos, found {len(todos_section)}")
        else:
            checks_passed.append(f"[C] Found 3 todos as expected")
    
        # Verify first todo is checked
        if todos_section[0].get("content") != "✨ Advanced search filters":
            errors.append(f"[X] First todo text incorrect: {todos_section[0].get('content')}")
        else:
            checks_passed.append(f"[C] First todo text incorrect: {todos_section[0].get('content')}")
        if not todos_section[0].get("properties", {}).get("checked"):
            errors.append("[X] First todo should be checked")
        else:
            checks_passed.append("[C] First todo should be checked")
    
        # Verify second todo is unchecked
        if todos_section[1].get("content") != "🎨 Customizable themes":
            errors.append(f"[X] Second todo text incorrect: {todos_section[1].get('content')}")
        else:
            checks_passed.append(f"[C] Second todo text incorrect: {todos_section[1].get('content')}")
        if todos_section[1].get("properties", {}).get("checked"):
            errors.append("[X] Second todo should be unchecked")
        else:
            checks_passed.append("[C] Second todo should be unchecked")
    
        # Verify third todo is unchecked
        if todos_section[2].get("content") != "📱 Offline mode support":
            errors.append(f"[X] Third todo text incorrect: {todos_section[2].get('content')}")
        else:
            checks_passed.append(f"[C] Third todo text incorrect: {todos_section[2].get('content')}")
        if todos_section[2].get("properties", {}).get("checked"):
            errors.append("[X] Third todo should be unchecked")
        else:
            checks_passed.append("[C] Third todo should be unchecked")
    
        # Find divider after todos
        todo_index = page_blocks_sorted.index(todos_section[2])
        divider_found = False
    
        if todo_index + 1 < len(page_blocks_sorted):
            if page_blocks_sorted[todo_index + 1].get("type") == "divider":
                divider_found = True
    
        if not divider_found:
            errors.append("[X] Divider not found after todos")
        else:
            checks_passed.append("[C] Divider found after todos")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_documentation_analytics_creation(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate Documentation Analytics page creation.
    
    Verification:
    - New page exists as child of Project Documentation
    - Heading structure correct
    - Total block count accurate
    - Per-page statistics with icons
    - Blue callout with most documented section
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    
    
    # Find Project Documentation
    try:
        proj_doc = _find_page_by_title(final_state_backend, "Project Documentation")
        if not proj_doc:
            errors.append("[X] Project Documentation page not found")
        else:
            checks_passed.append("[C] Project Documentation page found")
    
        proj_doc_id = proj_doc.get("_id")
    
        # Find Documentation Analytics page
        analytics_page = _find_page_by_title_and_parent(final_state_backend, "📊 Documentation Analytics", proj_doc_id)
        if not analytics_page:
            errors.append("[X] Documentation Analytics page not found as child of Project Documentation")
        else:
            checks_passed.append("[C] Documentation Analytics page found as child of Project Documentation")

        analytics_id = analytics_page.get("_id")

        # Get blocks for analytics page
        analytics_blocks = _get_blocks_for_page(final_state_backend, analytics_id)
        analytics_blocks_sorted = sorted(analytics_blocks, key=lambda b: b.get("order", 0))

        # Verify heading1
        if not analytics_blocks_sorted or analytics_blocks_sorted[0].get("type") != "heading1":
            errors.append("[X] First block is not heading1")
        else:
            checks_passed.append("[C] First block is heading1")
        if analytics_blocks_sorted[0].get("content") != "📊 Documentation Coverage Report":
            errors.append("[X] First heading text incorrect")
        else:
            checks_passed.append("[C] First heading text incorrect")

        # Verify heading2
        if len(analytics_blocks_sorted) < 2 or analytics_blocks_sorted[1].get("type") != "heading2":
            errors.append("[X] Second block is not heading2")
        else:
            checks_passed.append("[C] Second block is heading2")
        if analytics_blocks_sorted[1].get("content") != "📈 Block Distribution":
            errors.append("[X] Second heading text incorrect")
        else:
            checks_passed.append("[C] Second heading text incorrect")

        # Get descendant pages of Project Documentation using query-level filtering
        descendant_pages = _get_all_descendant_pages_from_backend(final_state_backend, proj_doc_id)
    
        # Exclude the Analytics page itself from the count
        descendant_pages = [p for p in descendant_pages if p.get("_id") != analytics_id]
    
        # Calculate total blocks across all descendants
        total_blocks = 0
        page_block_counts = {}
    
        for page in descendant_pages:
            page_id = page.get("_id")
            page_blocks = _get_blocks_for_page(final_state_backend, page_id)
            count = len(page_blocks)
            total_blocks += count
            page_block_counts[page_id] = (page, count, page_blocks)
    
        # Verify paragraph with total
        para_found = False
        for block in analytics_blocks_sorted[2:]:
            if block.get("type") == "paragraph":
                content = block.get("content", "")
                if f"Total blocks across all documentation: {total_blocks}" in content:
                    para_found = True
                    break
    
        if not para_found:
            errors.append(f"[X] Paragraph with total block count ({total_blocks}) not found")
        else:
            checks_passed.append(f"[C] Paragraph with total block count ({total_blocks}) found")
    
        # Verify each child page has a heading3 and statistics
        heading3_blocks = [b for b in analytics_blocks_sorted if b.get("type") == "heading3"]
    
        if len(heading3_blocks) != len(descendant_pages):
            errors.append(f"[X] Expected {len(descendant_pages)} heading3 blocks, found {len(heading3_blocks)}")
        else:
            checks_passed.append(f"[C] Expected {len(descendant_pages)} heading3 blocks, found {len(heading3_blocks)}")
    
        for page_id, (page, total_count, page_blocks) in page_block_counts.items():
            page_title = page.get("title", "")
            page_icon = page.get("icon", "")
        
            # Find matching heading3
            heading3_found = False
            for h3 in heading3_blocks:
                content = h3.get("content", "")
                if page_title in content and "Statistics" in content:
                    if page_icon and page_icon in content:
                        heading3_found = True
                    
                        # Get blocks after this heading3
                        h3_index = analytics_blocks_sorted.index(h3)
                        bullets_after = []
                        for b in analytics_blocks_sorted[h3_index + 1:]:
                            if b.get("type") == "bulletedList":
                                bullets_after.append(b)
                            elif b.get("type") in ["heading1", "heading2", "heading3"]:
                                break
                    
                        # Count block types for this page
                        headings = sum(1 for b in page_blocks if b.get("type") in ["heading1", "heading2", "heading3"])
                        paragraphs = sum(1 for b in page_blocks if b.get("type") == "paragraph")
                        code_blocks = sum(1 for b in page_blocks if b.get("type") == "code")
                        lists = sum(1 for b in page_blocks if b.get("type") in ["bulletedList", "numberedList"])
                    
                        # Verify bulleted list content
                        required_stats = {
                            f"Headings: {headings}",
                            f"Paragraphs: {paragraphs}",
                            f"Code blocks: {code_blocks}",
                            f"Lists: {lists}"
                        }
                    
                        found_stats = set()
                        for bullet in bullets_after:
                            content = bullet.get("content", "")
                            for stat in required_stats:
                                if stat in content:
                                    found_stats.add(stat)
                    
                        if len(found_stats) < 4:
                            errors.append(f"[X] Missing statistics for page '{page_title}'")
                        else:
                            checks_passed.append(f"[C] has statistics for page '{page_title}'")
                    
                        break
        
            if not heading3_found:
                errors.append(f"[X] Missing or incorrect heading3 for page '{page_title}'")
            else:
                checks_passed.append(f"[C] has or incorrect heading3 for page '{page_title}'")
    
        # Find most documented section
        max_page = max(page_block_counts.items(), key=lambda x: x[1][1])
        max_page_id, (max_page_obj, max_count, _) = max_page
        max_page_title = max_page_obj.get("title", "")
    
        # Verify blue callout with most documented section
        callout_found = False
        for block in analytics_blocks_sorted:
            if block.get("type") == "callout":
                bg = block.get("properties", {}).get("backgroundColor", "").lower()
                icon = block.get("properties", {}).get("icon", "")
                content = block.get("content", "")
                if "blue" in bg and icon == "💡":
                    if "Most documented section:" in content and max_page_title in content and str(max_count) in content:
                        callout_found = True
                        break
    
        if not callout_found:
            errors.append("[X] Blue callout with most documented section not found")
        else:
            checks_passed.append("[C] Blue callout with most documented section found")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_onboarding_interactive_checklist(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Interactive Onboarding Checklist on Onboarding Guide page."""
    errors: list[str] = []
    checks_passed: list[str] = []

    
    try:
        onboarding_page = _find_page_by_title(final_state_backend, "Onboarding Guide")
        if not onboarding_page:
            errors.append("[X] Onboarding Guide page not found")
        else:
            checks_passed.append("[C] Onboarding Guide page found")
    
        page_blocks = sorted(_get_blocks_for_page(final_state_backend, onboarding_page.get("_id")), key=lambda b: b.get("order", 0))
    
        # Find Interactive Onboarding Checklist heading
        checklist_heading = None
        for block in page_blocks:
            if block.get("type") == "heading2" and "interactive onboarding checklist" in block.get("content", "").lower():
                checklist_heading = block
                break
    
        if not checklist_heading:
            errors.append("[X] Interactive Onboarding Checklist heading_2 not found")
        else:
            checks_passed.append("[C] Interactive Onboarding Checklist heading_2 found")
    
        checklist_index = page_blocks.index(checklist_heading)
    
        # Verify intro paragraph
        if checklist_index + 1 >= len(page_blocks) or page_blocks[checklist_index + 1].get("type") != "paragraph":
            errors.append("[X] Intro paragraph not found after checklist heading")
        else:
            checks_passed.append("[C] Intro paragraph found after checklist heading")
        if "Complete these items in order for smooth onboarding:" not in page_blocks[checklist_index + 1].get("content", ""):
            errors.append("[X] Intro paragraph text incorrect")
        else:
            checks_passed.append("[C] Intro paragraph text incorrect")
    
        # Find three week headings
        week_headings = []
        for block in page_blocks[checklist_index:]:
            if block.get("type") == "heading3":
                content = block.get("content", "")
                if any(week in content for week in ["Week 1", "Week 2", "Week 3"]):
                    week_headings.append(block)
    
        if len(week_headings) < 3:
            errors.append(f"[X] Expected 3 week headings, found {len(week_headings)}")
        else:
            checks_passed.append(f"[C] Found 3 week headings as expected")
    
        # Verify each week has 4 todos
        for week_heading in week_headings:
            week_index = page_blocks.index(week_heading)
            todos_after = []
            for block in page_blocks[week_index + 1:]:
                if block.get("type") == "todo":
                    todos_after.append(block)
                elif block.get("type") in ["heading2", "heading3", "divider"]:
                    break
        
            if len(todos_after) < 4:
                errors.append(f"[X] Week '{week_heading.get('content')}' has fewer than 4 todos")
            else:
                checks_passed.append(f"[C] Week '{week_heading.get('content')}' has fewer than 4 todos")
        
            # Verify todos are unchecked
            for todo in todos_after[:4]:
                if todo.get("properties", {}).get("checked"):
                    errors.append(f"[X] Todo in '{week_heading.get('content')}' is checked")
                else:
                    checks_passed.append(f"[C] Todo in '{week_heading.get('content')}' is checked")
    
        # Find divider after todos
        divider_found = False
        callout_found = False
        quote_found = False
    
        for i, block in enumerate(page_blocks):
            if block.get("type") == "divider" and i > page_blocks.index(week_headings[-1]):
                divider_found = True
                # Check for callout after divider
                if i + 1 < len(page_blocks):
                    next_block = page_blocks[i + 1]
                    if next_block.get("type") == "callout":
                        bg = next_block.get("properties", {}).get("backgroundColor", "").lower()
                        content = next_block.get("content", "")
                        if "green" in bg and next_block.get("properties", {}).get("icon") == "🎯" and "Onboarding Progress Tracker" in content:
                            callout_found = True
                            # Check for paragraph and quote
                            if i + 2 < len(page_blocks):
                                para = page_blocks[i + 2]
                                if para.get("type") == "paragraph" and "Managers:" in para.get("content", ""):
                                    if i + 3 < len(page_blocks):
                                        quote_block = page_blocks[i + 3]
                                        if quote_block.get("type") == "quote":
                                            if "The secret of getting ahead is getting started." in quote_block.get("content", ""):
                                                quote_found = True
                break
    
        if not divider_found:
            errors.append("[X] Divider not found after todos")
        else:
            checks_passed.append("[C] Divider found after todos")
        if not callout_found:
            errors.append("[X] Green callout with progress tracker not found")
        else:
            checks_passed.append("[C] Green callout with progress tracker found")
        if not quote_found:
            errors.append("[X] Quote not found")
        else:
            checks_passed.append("[C] Quote found")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_sprint_planning_automation_creation(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Sprint Planning Automation page creation under Meeting Notes."""
    errors: list[str] = []
    checks_passed: list[str] = []

    
    # Find Meeting Notes page
    try:
        meeting_notes = _find_page_by_title(final_state_backend, "Meeting Notes")
        if not meeting_notes:
            errors.append("[X] Meeting Notes page not found")
        else:
            checks_passed.append("[C] Meeting Notes page found")

        # Find Sprint Planning - Jan 15 page
        sprint_planning = _find_page_with_all_title_patterns(final_state_backend, ["sprint planning", "jan 15"])
        if not sprint_planning:
            errors.append("[X] Sprint Planning - Jan 15 page not found")
        else:
            checks_passed.append("[C] Sprint Planning - Jan 15 page found")

        # Get todos from Sprint Planning page
        sprint_blocks = _get_blocks_for_page(final_state_backend, sprint_planning.get("_id"))
        sprint_todos = [b for b in sprint_blocks if b.get("type") == "todo"]
        total_todos = len(sprint_todos)
        completed_todos = sum(1 for t in sprint_todos if t.get("properties", {}).get("checked"))

        # Find attendees (bulletedList items)
        attendees = [b.get("content", "") for b in sprint_blocks if b.get("type") == "bulletedList"]

        # Find Sprint Planning Automation page
        automation_page = _find_page_by_title_and_parent(final_state_backend, "🤖 Sprint Planning Automation", meeting_notes.get("_id"))
    
        if not automation_page:
            errors.append("[X] Sprint Planning Automation page not found as child of Meeting Notes")
        else:
            checks_passed.append("[C] Sprint Planning Automation page found as child of Meeting Notes")
    
        # Get blocks for automation page
        auto_blocks = sorted(_get_blocks_for_page(final_state_backend, automation_page.get("_id")), key=lambda b: b.get("order", 0))
    
        # Verify heading1
        if not auto_blocks or auto_blocks[0].get("type") != "heading1":
            errors.append("[X] First block is not heading1")
        else:
            checks_passed.append("[C] First block is heading1")
        if auto_blocks[0].get("content") != "🤖 Sprint Planning Automation":
            errors.append("[X] First heading incorrect")
        else:
            checks_passed.append("[C] First heading incorrect")
    
        # Verify heading2
        if len(auto_blocks) < 2 or auto_blocks[1].get("type") != "heading2":
            errors.append("[X] Second block is not heading2")
        else:
            checks_passed.append("[C] Second block is heading2")
        if auto_blocks[1].get("content") != "📋 Current Sprint Analysis":
            errors.append("[X] Second heading incorrect")
        else:
            checks_passed.append("[C] Second heading incorrect")
    
        # Find callout with sprint health
        callout_found = False
        for block in auto_blocks:
            if block.get("type") == "callout":
                content = block.get("content", "")
                bg = block.get("properties", {}).get("backgroundColor", "").lower()
            
                if "Sprint health:" in content and str(completed_todos) in content and str(total_todos) in content:
                    # Verify color matches completion status
                    if completed_todos == total_todos and "green" in bg:
                        callout_found = True
                    elif completed_todos < total_todos and "yellow" in bg:
                        callout_found = True
    
        if not callout_found:
            errors.append("[X] Callout with correct sprint health and color not found")
        else:
            checks_passed.append("[C] Callout with correct sprint health and color found")
    
        # Find Team Participation heading
        team_heading = None
        for block in auto_blocks:
            if block.get("type") == "heading2" and "team participation" in block.get("content", "").lower():
                team_heading = block
                break
    
        if not team_heading:
            errors.append("[X] Team Participation heading_2 not found")
        else:
            checks_passed.append("[C] Team Participation heading_2 found")
    
        # Verify attendee todos
        team_index = auto_blocks.index(team_heading)
        todos_after = [b for b in auto_blocks[team_index + 1:] if b.get("type") == "todo"]
    
        if len(todos_after) < len(attendees):
            errors.append(f"[X] Expected at least {len(attendees)} attendee todos")
        else:
            checks_passed.append(f"[C] Expected at least {len(attendees)} attendee todos")
    
        # Find quote at end
        quote_found = False
        divider_found = False
        for i, block in enumerate(auto_blocks):
            if block.get("type") == "divider":
                divider_found = True
                if i + 1 < len(auto_blocks):
                    next_block = auto_blocks[i + 1]
                    if next_block.get("type") == "quote":
                        if "Automation is not about replacing humans, but empowering them to focus on what matters." in next_block.get("content", ""):
                            quote_found = True
    
        if not divider_found or not quote_found:
            errors.append("[X] Divider and quote not found at end")
        else:
            checks_passed.append("[C] Divider and quote found at end")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_sprint_planning_post_review(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Post-Sprint Review section on Sprint Planning - Jan 15 page."""
    errors: list[str] = []
    checks_passed: list[str] = []

    
    # Find Sprint Planning - Jan 15
    try:
        sprint_page = _find_page_with_all_title_patterns(final_state_backend, ["sprint planning", "jan 15"])
    
        if not sprint_page:
            errors.append("[X] Sprint Planning - Jan 15 page not found")
        else:
            checks_passed.append("[C] Sprint Planning - Jan 15 page found")
    
        page_blocks = sorted(_get_blocks_for_page(final_state_backend, sprint_page.get("_id")), key=lambda b: b.get("order", 0))
    
        # Find Action Items section
        action_items_heading = None
        for block in page_blocks:
            if block.get("type") == "heading2" and "action items" in block.get("content", "").lower():
                action_items_heading = block
                break
    
        if not action_items_heading:
            errors.append("[X] Action Items heading not found")
        else:
            checks_passed.append("[C] Action Items heading found")
    
        action_index = page_blocks.index(action_items_heading)
    
        # Find Post-Sprint Review heading (should come after Action Items)
        review_heading = None
        for block in page_blocks[action_index:]:
            if block.get("type") == "heading2" and "post-sprint review" in block.get("content", "").lower():
                review_heading = block
                break
    
        if not review_heading:
            errors.append("[X] Post-Sprint Review heading_2 not found after Action Items")
        else:
            checks_passed.append("[C] Post-Sprint Review heading_2 found after Action Items")
    
        review_index = page_blocks.index(review_heading)
    
        # Verify divider before review heading
        if review_index > 0:
            prev_block = page_blocks[review_index - 1]
            if prev_block.get("type") != "divider":
                errors.append("[X] Divider not found before Post-Sprint Review heading")
            else:
                checks_passed.append("[C] Divider found before Post-Sprint Review heading")
    
        # Verify orange callout after heading
        if review_index + 1 >= len(page_blocks):
            errors.append("[X] No blocks found after Post-Sprint Review heading")
        else:
            checks_passed.append("[C] blocks found after Post-Sprint Review heading")
    
        callout = page_blocks[review_index + 1]
        if callout.get("type") != "callout":
            errors.append("[X] Callout not found after Post-Sprint Review heading")
        else:
            checks_passed.append("[C] Callout found after Post-Sprint Review heading")
    
        bg = callout.get("properties", {}).get("backgroundColor", "").lower()
        content = callout.get("content", "")
        if "orange" not in bg or "⏰" not in content or "Review deadline: January 29, 2024" not in content:
            errors.append("[X] Orange callout with clock icon and deadline not correct")
        else:
            checks_passed.append("[C] Orange callout with clock icon and deadline correct")
    
        # Find Sprint Velocity Metrics heading3
        velocity_heading = None
        retro_heading = None
    
        for block in page_blocks[review_index:]:
            if block.get("type") == "heading3":
                content = block.get("content", "")
                if "sprint velocity metrics" in content.lower():
                    velocity_heading = block
                elif "retrospective notes" in content.lower():
                    retro_heading = block
    
        if not velocity_heading:
            errors.append("[X] Sprint Velocity Metrics heading_3 not found")
        else:
            checks_passed.append("[C] Sprint Velocity Metrics heading_3 found")
    
        if not retro_heading:
            errors.append("[X] Retrospective Notes heading_3 not found")
        else:
            checks_passed.append("[C] Retrospective Notes heading_3 found")
    
        # Verify numbered lists under velocity
        velocity_index = page_blocks.index(velocity_heading)
        numbered_lists = []
        for block in page_blocks[velocity_index + 1:]:
            if block.get("type") == "numberedList":
                numbered_lists.append(block)
            elif block.get("type") in ["heading2", "heading3"]:
                break
    
        if len(numbered_lists) < 3:
            errors.append("[X] Expected 3 numbered list items under Sprint Velocity Metrics")
        else:
            checks_passed.append("[C] Expected 3 numbered list items under Sprint Velocity Metrics")
    
        # Verify retrospective bullets
        retro_index = page_blocks.index(retro_heading)
        bullets = []
        for block in page_blocks[retro_index + 1:]:
            if block.get("type") == "bulletedList":
                bullets.append(block)
            elif block.get("type") in ["heading2", "heading3", "quote"]:
                break
    
        if len(bullets) < 3:
            errors.append("[X] Expected at least 3 bulleted items under Retrospective Notes")
        else:
            checks_passed.append("[C] Expected at least 3 bulleted items under Retrospective Notes")
    
        # Find quote at end
        quote_found = False
        for block in page_blocks[review_index:]:
            if block.get("type") == "quote":
                if "Continuous improvement is better than delayed perfection." in block.get("content", ""):
                    quote_found = True
                    break
    
        if not quote_found:
            errors.append("[X] Quote with exact text not found")
        else:
            checks_passed.append("[C] Quote with exact text found")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_team_performance_review_creation(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Team Performance Review page creation under Meeting Notes."""
    errors: list[str] = []
    checks_passed: list[str] = []

    
    # Find Meeting Notes
    try:
        meeting_notes = _find_page_by_title(final_state_backend, "Meeting Notes")
        if not meeting_notes:
            errors.append("[X] Meeting Notes page not found")
        else:
            checks_passed.append("[C] Meeting Notes page found")

        # Find Team Performance Review page
        review_page = _find_page_by_title_and_parent(final_state_backend, "👥 Team Performance Review", meeting_notes.get("_id"))
        if not review_page:
            errors.append("[X] Team Performance Review page not found as child of Meeting Notes")
        else:
            checks_passed.append("[C] Team Performance Review page found as child of Meeting Notes")

        # Get Sprint Planning - Jan 15 todos for comparison
        sprint_page = _find_page_with_all_title_patterns(final_state_backend, ["sprint planning", "jan 15"])
        if not sprint_page:
            errors.append("[X] Sprint Planning - Jan 15 page not found")
        else:
            checks_passed.append("[C] Sprint Planning - Jan 15 page found")
    
        sprint_blocks = _get_blocks_for_page(final_state_backend, sprint_page.get("_id"))
        sprint_todos = [b for b in sprint_blocks if b.get("type") == "todo"]
        total_todos = len(sprint_todos)
        completed_todos = sum(1 for t in sprint_todos if t.get("properties", {}).get("checked"))
    
        # Get blocks for review page
        review_blocks = sorted(_get_blocks_for_page(final_state_backend, review_page.get("_id")), key=lambda b: b.get("order", 0))
    
        # Verify heading structure
        if not review_blocks or review_blocks[0].get("type") != "heading1":
            errors.append("[X] First block is not heading1")
        else:
            checks_passed.append("[C] First block is heading1")
        if review_blocks[0].get("content") != "👥 Team Performance Review":
            errors.append("[X] First heading incorrect")
        else:
            checks_passed.append("[C] First heading incorrect")
    
        # Find callout with statistics
        callout_found = False
        for block in review_blocks:
            if block.get("type") == "callout":
                content = block.get("content", "")
                bg = block.get("properties", {}).get("backgroundColor", "").lower()
                if "green" in bg and block.get("properties", {}).get("icon") == "🏆":
                    if "Sprint Success:" in content and str(completed_todos) in content and str(total_todos) in content:
                        # Calculate percentage
                        if total_todos > 0:
                            percentage = int((completed_todos / total_todos) * 100)
                            if str(percentage) in content:
                                callout_found = True
    
        if not callout_found:
            errors.append("[X] Green callout with trophy icon and correct statistics not found")
        else:
            checks_passed.append("[C] Green callout with trophy icon and correct statistics found")
    
        # Find Recommendations heading
        reco_heading = None
        for block in review_blocks:
            if block.get("type") == "heading2" and "recommendations" in block.get("content", "").lower():
                reco_heading = block
                break
    
        if not reco_heading:
            errors.append("[X] Recommendations heading_2 not found")
        else:
            checks_passed.append("[C] Recommendations heading_2 found")
    
        # Find quote after recommendations
        reco_index = review_blocks.index(reco_heading)
        quote_found = False
        for block in review_blocks[reco_index:]:
            if block.get("type") == "quote":
                content = block.get("content", "")
                if "team has shown strong execution" in content.lower():
                    quote_found = True
                    break
    
        if not quote_found:
            errors.append("[X] Quote not found after Recommendations")
        else:
            checks_passed.append("[C] Quote found after Recommendations")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_weekly_standup_mid_week_check(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Mid-Week Progress Check insertion on Weekly Standup Template."""
    errors: list[str] = []
    checks_passed: list[str] = []

    
    
    # Find Weekly Standup Template page
    try:
        standup_page = _find_page_by_title(final_state_backend, "Weekly Standup Template")
        if not standup_page:
            errors.append("[X] Weekly Standup Template page not found")
        else:
            checks_passed.append("[C] Weekly Standup Template page found")
    
        page_blocks = sorted(_get_blocks_for_page(final_state_backend, standup_page.get("_id")), key=lambda b: b.get("order", 0))
    
        # Find "What I plan to do next week" heading
        plan_heading = None
        blockers_heading = None
    
        for block in page_blocks:
            if block.get("type") == "heading2":
                content = block.get("content", "").lower()
                if "what i plan to do next week" in content:
                    plan_heading = block
                elif "blockers" in content:
                    blockers_heading = block
    
        if not plan_heading:
            errors.append("[X] What I plan to do next week heading not found")
        else:
            checks_passed.append("[C] What I plan to do next week heading found")
        if not blockers_heading:
            errors.append("[X] Blockers heading not found")
        else:
            checks_passed.append("[C] Blockers heading found")
    
        # Find Mid-Week Progress Check heading
        mid_week_heading = None
        for block in page_blocks:
            if block.get("type") == "heading2" and "mid-week progress check" in block.get("content", "").lower():
                mid_week_heading = block
                break
    
        if not mid_week_heading:
            errors.append("[X] Mid-Week Progress Check heading_2 not found")
        else:
            checks_passed.append("[C] Mid-Week Progress Check heading_2 found")
    
        # Verify position between plan and blockers
        plan_index = page_blocks.index(plan_heading)
        mid_week_index = page_blocks.index(mid_week_heading)
        blockers_index = page_blocks.index(blockers_heading)
    
        if not (plan_index < mid_week_index < blockers_index):
            errors.append("[X] Mid-Week Progress Check not positioned correctly")
        else:
            checks_passed.append("[C] Mid-Week Progress Check positioned correctly")
    
        # Verify three todos after mid-week heading
        expected_todos = [
            "🔍 Review code quality metrics",
            "📈 Update progress on sprint goals",
            "💬 Schedule sync with product team"
        ]
    
        todos_after = []
        for block in page_blocks[mid_week_index + 1:]:
            if block.get("type") == "todo":
                todos_after.append(block)
            elif block.get("type") in ["heading2", "heading3", "callout"]:
                break
            if len(todos_after) >= 3:
                break
    
        if len(todos_after) < 3:
            errors.append(f"[X] Expected 3 todos, found {len(todos_after)}")
        else:
            checks_passed.append(f"[C] Found 3 todos as expected")
    
        for i, expected in enumerate(expected_todos):
            if todos_after[i].get("content") != expected:
                errors.append(f"[X] Todo {i+1} text incorrect")
            else:
                checks_passed.append(f"[C] Todo {i+1} text incorrect")
            if todos_after[i].get("properties", {}).get("checked"):
                errors.append(f"[X] Todo {i+1} should be unchecked")
            else:
                checks_passed.append(f"[C] Todo {i+1} should be unchecked")
    
        # Verify yellow callout
        callout_found = False
        for block in page_blocks[mid_week_index:blockers_index]:
            if block.get("type") == "callout":
                bg = block.get("properties", {}).get("backgroundColor", "").lower()
                content = block.get("content", "")
                if "yellow" in bg and block.get("properties", {}).get("icon") == "💡" and "Remember to update your progress by Wednesday EOD" in content:
                    callout_found = True
                    break
    
        if not callout_found:
            errors.append("[X] Yellow callout with correct text not found")
        else:
            checks_passed.append("[C] Yellow callout with correct text found")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_sprint_planning_follow_up_status(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Follow-up Status section on Sprint Planning - Jan 15 page."""
    errors: list[str] = []
    checks_passed: list[str] = []

    
    # Find Sprint Planning - Jan 15
    try:
        sprint_page = _find_page_with_all_title_patterns(final_state_backend, ["sprint planning", "jan 15"])
    
        if not sprint_page:
            errors.append("[X] Sprint Planning - Jan 15 page not found")
        else:
            checks_passed.append("[C] Sprint Planning - Jan 15 page found")
    
        page_blocks = sorted(_get_blocks_for_page(final_state_backend, sprint_page.get("_id")), key=lambda b: b.get("order", 0))
    
        # Find Action Items section todos
        action_todos = []
        in_action_section = False
    
        for block in page_blocks:
            if block.get("type") == "heading2" and "action items" in block.get("content", "").lower():
                in_action_section = True
                continue
            if in_action_section:
                if block.get("type") == "todo":
                    action_todos.append(block)
                elif block.get("type") == "heading2":
                    break
    
        if not action_todos:
            errors.append("[X] No todos found in Action Items section")
        else:
            checks_passed.append("[C] todos found in Action Items section")
    
        # Find Follow-up Status heading
        followup_heading = None
        for block in page_blocks:
            if block.get("type") == "heading2" and "follow-up status" in block.get("content", "").lower():
                followup_heading = block
                break
    
        if not followup_heading:
            errors.append("[X] Follow-up Status heading_2 not found")
        else:
            checks_passed.append("[C] Follow-up Status heading_2 found")
    
        followup_index = page_blocks.index(followup_heading)
    
        # Verify callouts after follow-up heading (one for each todo)
        callouts_found = []
        for block in page_blocks[followup_index + 1:]:
            if block.get("type") == "callout":
                callouts_found.append(block)
            elif block.get("type") in ["heading1", "heading2", "divider"]:
                break
    
        if len(callouts_found) < len(action_todos):
            errors.append(f"[X] Expected {len(action_todos)} callouts, found {len(callouts_found)}")
        else:
            checks_passed.append(f"[C] Expected {len(action_todos)} callouts, found {len(callouts_found)}")
    
        # Verify each callout matches a todo
        for i, todo in enumerate(action_todos):
            todo_text = todo.get("content", "")
            todo_checked = todo.get("properties", {}).get("checked", False)
        
            if i < len(callouts_found):
                callout = callouts_found[i]
                bg = callout.get("properties", {}).get("backgroundColor", "").lower()
                content = callout.get("content", "")
            
                # Verify color matches status
                if todo_checked and "green" not in bg:
                    errors.append(f"[X] Callout {i+1} should have green background for completed todo")
                else:
                    checks_passed.append(f"[C] Callout {i+1} should have green background for completed todo")
                if not todo_checked and "orange" not in bg:
                    errors.append(f"[X] Callout {i+1} should have orange background for pending todo")
                else:
                    checks_passed.append(f"[C] Callout {i+1} should have orange background for pending todo")
            
                # Verify icon
                expected_icon = "✅" if todo_checked else "⏳"
                if expected_icon not in content:
                    errors.append(f"[X] Callout {i+1} missing expected icon")
                else:
                    checks_passed.append(f"[C] Callout {i+1} has expected icon")
            
                # Verify contains todo text and status
                status = "Completed" if todo_checked else "Pending"
                if f"Status:" not in content or status not in content:
                    errors.append(f"[X] Callout {i+1} missing status text")
                else:
                    checks_passed.append(f"[C] Callout {i+1} has status text")
    
        # Find divider and paragraph with review date
        divider_found = False
        review_date_found = False
    
        for i, block in enumerate(page_blocks[followup_index:]):
            if block.get("type") == "divider":
                divider_found = True
                if i + 1 < len(page_blocks[followup_index:]):
                    next_block = page_blocks[followup_index + i + 1]
                    if next_block.get("type") == "paragraph":
                        if "Next Review Date: January 29, 2024" in next_block.get("content", ""):
                            review_date_found = True
                break
    
        if not divider_found:
            errors.append("[X] Divider not found after callouts")
        else:
            checks_passed.append("[C] Divider found after callouts")
        if not review_date_found:
            errors.append("[X] Review date paragraph not found")
        else:
            checks_passed.append("[C] Review date paragraph found")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_learning_path_tracker_creation(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Learning Path Tracker page creation under Onboarding Guide."""
    errors: list[str] = []
    checks_passed: list[str] = []

    
    # Find Onboarding Guide
    try:
        onboarding = _find_page_by_title(final_state_backend, "Onboarding Guide")
        if not onboarding:
            errors.append("[X] Onboarding Guide page not found")
        else:
            checks_passed.append("[C] Onboarding Guide page found")
    
        onboarding_id = onboarding.get("_id")
    
        # Find Getting Started page
        getting_started = _find_page_by_title(final_state_backend, "Getting Started")
    
        # Get numbered items from Onboarding Guide
        onboarding_blocks = _get_blocks_for_page(final_state_backend, onboarding_id)
        onboarding_numbered = [b for b in onboarding_blocks if b.get("type") == "numberedList"]
    
        # Get todos from Getting Started if it exists
        getting_started_todos = []
        if getting_started:
            gs_blocks = _get_blocks_for_page(final_state_backend, getting_started.get("_id"))
            getting_started_todos = [b for b in gs_blocks if b.get("type") == "todo"]
    
        # Find Learning Path Tracker page using query-level filter
        tracker_result = final_state_backend.query({
            "collection": "pages",
            "filter": {
                "title": "🎓 Learning Path Tracker",
                "parentId": onboarding_id
            }
        })
        tracker_page = tracker_result[0] if isinstance(tracker_result, list) and tracker_result else None
    
        if not tracker_page:
            errors.append("[X] Learning Path Tracker page not found as child of Onboarding Guide")
        else:
            checks_passed.append("[C] Learning Path Tracker page found as child of Onboarding Guide")
    
        # Get blocks for tracker page
        tracker_blocks = sorted(_get_blocks_for_page(final_state_backend, tracker_page.get("_id")), key=lambda b: b.get("order", 0))
    
        # Verify heading1
        if not tracker_blocks or tracker_blocks[0].get("type") != "heading1":
            errors.append("[X] First block is not heading1")
        else:
            checks_passed.append("[C] First block is heading1")
        if tracker_blocks[0].get("content") != "🎓 Learning Path Tracker":
            errors.append("[X] First heading incorrect")
        else:
            checks_passed.append("[C] First heading incorrect")
    
        # Verify green callout
        if len(tracker_blocks) < 2 or tracker_blocks[1].get("type") != "callout":
            errors.append("[X] Callout not found after heading1")
        else:
            checks_passed.append("[C] Callout found after heading1")
    
        callout = tracker_blocks[1]
        bg = callout.get("properties", {}).get("backgroundColor", "").lower()
        content = callout.get("content", "")
        if "green" not in bg or "🚀" not in content or "Your personalized learning journey starts here!" not in content:
            errors.append("[X] Green callout with rocket icon not correct")
        else:
            checks_passed.append("[C] Green callout with rocket icon correct")
    
        # Find Onboarding Modules heading
        modules_heading = None
        tasks_heading = None
        summary_heading = None
    
        for block in tracker_blocks:
            if block.get("type") == "heading2":
                content = block.get("content", "")
                if "onboarding modules" in content.lower():
                    modules_heading = block
                elif "getting started tasks" in content.lower():
                    tasks_heading = block
                elif "progress summary" in content.lower():
                    summary_heading = block
    
        if not modules_heading:
            errors.append("[X] Onboarding Modules heading_2 not found")
        else:
            checks_passed.append("[C] Onboarding Modules heading_2 found")
    
        # Verify todos match numbered items from Onboarding (all unchecked)
        modules_index = tracker_blocks.index(modules_heading)
        module_todos = []
        for block in tracker_blocks[modules_index + 1:]:
            if block.get("type") == "todo":
                module_todos.append(block)
            elif block.get("type") == "heading2":
                break
    
        if len(module_todos) < len(onboarding_numbered):
            errors.append(f"[X] Expected at least {len(onboarding_numbered)} module todos")
        else:
            checks_passed.append(f"[C] Expected at least {len(onboarding_numbered)} module todos")
    
        # Verify all module todos are unchecked
        for todo in module_todos[:len(onboarding_numbered)]:
            if todo.get("properties", {}).get("checked"):
                errors.append("[X] Module todo should be unchecked")
            else:
                checks_passed.append("[C] Module todo should be unchecked")
    
        # Find quote with progress summary
        quote_found = False
        for block in tracker_blocks:
            if block.get("type") == "quote":
                content = block.get("content", "")
                if "Total learning items:" in content and "Progress:" in content:
                    quote_found = True
                    break
    
        if not quote_found:
            errors.append("[X] Quote with progress summary not found")
        else:
            checks_passed.append("[C] Quote with progress summary found")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_onboarding_completion_tracker(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Onboarding Completion Tracker on Onboarding Guide page."""
    errors: list[str] = []
    checks_passed: list[str] = []

    
    
    # Find Onboarding Guide
    try:
        onboarding = _find_page_by_title(final_state_backend, "Onboarding Guide")
        if not onboarding:
            errors.append("[X] Onboarding Guide page not found")
        else:
            checks_passed.append("[C] Onboarding Guide page found")
    
        page_blocks = sorted(_get_blocks_for_page(final_state_backend, onboarding.get("_id")), key=lambda b: b.get("order", 0))
    
        # Count numbered list items
        numbered_items = [b for b in page_blocks if b.get("type") == "numberedList"]
        total_steps = len(numbered_items)
        estimated_days = (total_steps + 1) // 2  # Rounded up
    
        # Find completion tracker heading
        tracker_heading = None
        for block in page_blocks:
            if block.get("type") == "heading2" and "onboarding completion tracker" in block.get("content", "").lower():
                tracker_heading = block
                break
    
        if not tracker_heading:
            errors.append("[X] Onboarding Completion Tracker heading_2 not found")
        else:
            checks_passed.append("[C] Onboarding Completion Tracker heading_2 found")
    
        tracker_index = page_blocks.index(tracker_heading)
    
        # Verify callout with step count and estimated days
        callout_found = False
        if tracker_index + 1 < len(page_blocks):
            callout = page_blocks[tracker_index + 1]
            if callout.get("type") == "callout":
                bg = callout.get("properties", {}).get("backgroundColor", "").lower()
                content = callout.get("content", "")
                if "blue" in bg and block.get("properties", {}).get("icon") == "🎯":
                    if f"Total onboarding steps: {total_steps}" in content and f"Estimated time: {estimated_days} days" in content:
                        callout_found = True
    
        if not callout_found:
            errors.append("[X] Blue callout with correct step count and estimated days not found")
        else:
            checks_passed.append("[C] Blue callout with correct step count and estimated days found")
    
        # Find Progress Visualization heading3
        viz_heading = None
        for block in page_blocks[tracker_index:]:
            if block.get("type") == "heading3" and "progress visualization" in block.get("content", "").lower():
                viz_heading = block
                break
    
        if not viz_heading:
            errors.append("[X] Progress Visualization heading_3 not found")
        else:
            checks_passed.append("[C] Progress Visualization heading_3 found")
    
        viz_index = page_blocks.index(viz_heading)
    
        # Verify todos (one for each numbered list item, all prefixed with "Complete: ")
        todos_after_viz = []
        for block in page_blocks[viz_index + 1:]:
            if block.get("type") == "todo":
                todos_after_viz.append(block)
            elif block.get("type") in ["heading2", "heading3", "divider"]:
                break
    
        if len(todos_after_viz) < total_steps:
            errors.append(f"[X] Expected {total_steps} todos, found {len(todos_after_viz)}")
        else:
            checks_passed.append(f"[C] Expected {total_steps} todos, found {len(todos_after_viz)}")
    
        # Verify todos are unchecked and have "Complete: " prefix
        for todo in todos_after_viz[:total_steps]:
            if todo.get("properties", {}).get("checked"):
                errors.append("[X] Todo should be unchecked")
            else:
                checks_passed.append("[C] Todo should be unchecked")
            if not todo.get("content", "").startswith("Complete: "):
                errors.append("[X] Todo should start with 'Complete: '")
            else:
                checks_passed.append("[C] Todo should start with 'Complete: '")
    
        # Find divider and Completion Rewards heading3
        rewards_heading = None
        for block in page_blocks[viz_index:]:
            if block.get("type") == "heading3" and "completion rewards" in block.get("content", "").lower():
                rewards_heading = block
                break
    
        if not rewards_heading:
            errors.append("[X] Completion Rewards heading_3 not found")
        else:
            checks_passed.append("[C] Completion Rewards heading_3 found")
    
        rewards_index = page_blocks.index(rewards_heading)
    
        # Verify badge system bullets
        bullets_after = []
        for block in page_blocks[rewards_index + 1:]:
            if block.get("type") == "bulletedList":
                bullets_after.append(block)
            elif block.get("type") in ["heading2", "heading3", "paragraph"]:
                break
    
        if len(bullets_after) < 3:
            errors.append("[X] Expected 3 badge bullets (Bronze, Silver, Gold)")
        else:
            checks_passed.append("[C] Expected 3 badge bullets (Bronze, Silver, Gold)")
    
        # Verify italic paragraph at end
        italic_found = False
        for block in page_blocks[rewards_index:]:
            if block.get("type") == "paragraph":
                content = block.get("content", "")
                if "Check off items above as you complete each onboarding step" in content:
                    italic_found = True
                    break
    
        if not italic_found:
            errors.append("[X] Italic paragraph with instructions not found")
        else:
            checks_passed.append("[C] Italic paragraph with instructions found")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_api_endpoint_reference(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate API Endpoint Reference section on API Documentation page."""
    errors: list[str] = []
    checks_passed: list[str] = []

    
    
    # Find API Documentation page
    try:
        api_page = _find_page_by_title(final_state_backend, "API Documentation")
        if not api_page:
            errors.append("[X] API Documentation page not found")
        else:
            checks_passed.append("[C] API Documentation page found")
    
        page_blocks = sorted(_get_blocks_for_page(final_state_backend, api_page.get("_id")), key=lambda b: b.get("order", 0))
    
        # Find API Endpoint Reference heading
        ref_heading = None
        for block in page_blocks:
            if block.get("type") == "heading2" and "api endpoint reference" in block.get("content", "").lower():
                ref_heading = block
                break
    
        if not ref_heading:
            errors.append("[X] API Endpoint Reference heading_2 not found")
        else:
            checks_passed.append("[C] API Endpoint Reference heading_2 found")
    
        ref_index = page_blocks.index(ref_heading)
    
        # Find three endpoint category headings
        get_heading = None
        post_heading = None
        put_heading = None
    
        for block in page_blocks[ref_index:]:
            if block.get("type") == "heading3":
                content = block.get("content", "")
                if "get endpoints" in content.lower():
                    get_heading = block
                elif "post endpoints" in content.lower():
                    post_heading = block
                elif "put endpoints" in content.lower():
                    put_heading = block
    
        if not all([get_heading, post_heading, put_heading]):
            errors.append("[X] Missing one or more endpoint category headings")
        else:
            checks_passed.append("[C] has one or more endpoint category headings")
    
        # Verify GET endpoints have numbered lists
        get_index = page_blocks.index(get_heading)
        get_numbered = []
        for block in page_blocks[get_index + 1:]:
            if block.get("type") == "numberedList":
                get_numbered.append(block)
            elif block.get("type") in ["heading2", "heading3"]:
                break
    
        if len(get_numbered) < 3:
            errors.append("[X] Expected at least 3 GET endpoints in numbered list")
        else:
            checks_passed.append("[C] Expected at least 3 GET endpoints in numbered list")
    
        # Verify POST endpoints
        post_index = page_blocks.index(post_heading)
        post_numbered = []
        for block in page_blocks[post_index + 1:]:
            if block.get("type") == "numberedList":
                post_numbered.append(block)
            elif block.get("type") in ["heading2", "heading3"]:
                break
    
        if len(post_numbered) < 2:
            errors.append("[X] Expected at least 2 POST endpoints in numbered list")
        else:
            checks_passed.append("[C] Expected at least 2 POST endpoints in numbered list")
    
        # Find code block with bash/curl example
        code_found = False
        for block in page_blocks[ref_index:]:
            if block.get("type") == "code":
                lang = block.get("properties", {}).get("language", "")
                content = block.get("content", "")
                if lang == "bash" and "curl" in content and "Authorization: Bearer TOKEN" in content:
                    code_found = True
                    break
    
        if not code_found:
            errors.append("[X] Bash code block with curl example not found")
        else:
            checks_passed.append("[C] Bash code block with curl example found")
    
        # Find gray callout with authentication note
        callout_found = False
        for block in page_blocks[ref_index:]:
            if block.get("type") == "callout":
                bg = block.get("properties", {}).get("backgroundColor", "").lower()
                content = block.get("content", "")
                if "gray" in bg and block.get("properties", {}).get("icon") == "🔐" and "All endpoints require authentication via Bearer token" in content:
                    callout_found = True
                    break
    
        if not callout_found:
            errors.append("[X] Gray callout with authentication note not found")
        else:
            checks_passed.append("[C] Gray callout with authentication note found")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

    # Simplified/stub implementations for the remaining complex validation functions
    # These can be expanded based on specific requirements
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
def _validate_design_system_reorganization(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Design System page reorganization with Typography moved after Color Palette."""
    errors: list[str] = []
    checks_passed: list[str] = []

    
    
    try:
        design_page = _find_page_by_title(final_state_backend, "Design System")
        if not design_page:
            errors.append("[X] Design System page not found")
        else:
            checks_passed.append("[C] Design System page found")
    
        page_blocks = sorted(_get_blocks_for_page(final_state_backend, design_page.get("_id")), key=lambda b: b.get("order", 0))
    
        # Find Color Palette and Typography headings
        color_heading = None
        typo_heading = None
    
        for block in page_blocks:
            if block.get("type") == "heading2":
                content = block.get("content", "").lower()
                if "color palette" in content:
                    color_heading = block
                elif "typography" in content:
                    typo_heading = block
    
        if not color_heading or not typo_heading:
            errors.append("[X] Color Palette or Typography heading not found")
        else:
            checks_passed.append("[C] Color Palette or Typography heading found")
    
        color_index = page_blocks.index(color_heading)
        typo_index = page_blocks.index(typo_heading)
    
        # Verify Typography appears after Color Palette
        if typo_index <= color_index:
            errors.append("[X] Typography section should appear after Color Palette")
        else:
            checks_passed.append("[C] Typography section should appear after Color Palette")
    
        # Find Color Usage Guidelines heading3
        guidelines_found = False
        for block in page_blocks[color_index:typo_index]:
            if block.get("type") == "heading3" and "color usage guidelines" in block.get("content", "").lower():
                guidelines_found = True
                break
    
        if not guidelines_found:
            errors.append("[X] Color Usage Guidelines heading_3 not found")
        else:
            checks_passed.append("[C] Color Usage Guidelines heading_3 found")
    
        # Find blue callout
        callout_found = False
        for block in page_blocks[color_index:typo_index]:
            if block.get("type") == "callout":
                bg = block.get("properties", {}).get("backgroundColor", "").lower()
                content = block.get("content", "")
                if "blue" in bg and "4.5:1" in content:
                    callout_found = True
                    break
    
        if not callout_found:
            errors.append("[X] Blue callout with contrast ratio not found")
        else:
            checks_passed.append("[C] Blue callout with contrast ratio found")
    
        # Verify CSS code blocks
        css_blocks = [b for b in page_blocks[color_index:typo_index] 
                      if b.get("type") == "code" and b.get("properties", {}).get("language") == "css"]
    
        if len(css_blocks) < 4:
            errors.append(f"[X] Expected 4 CSS code blocks, found {len(css_blocks)}")
        else:
            checks_passed.append(f"[C] Found 4 CSS code blocks as expected")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_product_requirements_technical_specs(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Technical Specifications section on Product Requirements page."""
    errors: list[str] = []
    checks_passed: list[str] = []

    
    
    try:
        pr_page = _find_page_by_title(final_state_backend, "Comprehensive Product Requirements Document")
        if not pr_page:
            errors.append("[X] Comprehensive Product Requirements Document page not found")
        else:
            checks_passed.append("[C] Comprehensive Product Requirements Document page found")
    
        page_blocks = sorted(_get_blocks_for_page(final_state_backend, pr_page.get("_id")), key=lambda b: b.get("order", 0))
    
        # Find Overview - Part 3 heading
        overview_part3 = None
        for block in page_blocks:
            if block.get("type") == "heading3" and "Overview - Part 3" in block.get("content", ""):
                overview_part3 = block
                break
    
        if not overview_part3:
            errors.append("[X] Overview - Part 3 heading not found")
        else:
            checks_passed.append("[C] Overview - Part 3 heading found")
    
        overview_part3_index = page_blocks.index(overview_part3)
    
        # Find Technical Specifications heading
        tech_heading = None
        for block in page_blocks:
            if block.get("type") == "heading2" and "technical specifications" in block.get("content", "").lower():
                tech_heading = block
                break
    
        if not tech_heading:
            errors.append("[X] Technical Specifications heading_2 not found")
        else:
            checks_passed.append("[C] Technical Specifications heading_2 found")
    
        tech_index = page_blocks.index(tech_heading)
    
        # Verify Technical Specifications appears after Overview - Part 3
        if tech_index <= overview_part3_index:
            errors.append("[X] Technical Specifications must appear after Overview - Part 3 heading")
        else:
            checks_passed.append("[C] Technical Specifications must appear after Overview - Part 3 heading")
    
        # Find User Stories heading to verify positioning before it
        user_stories_heading = None
        for block in page_blocks:
            if block.get("type") == "heading2" and "User Stories" in block.get("content", ""):
                user_stories_heading = block
                break
    
        if user_stories_heading:
            user_stories_index = page_blocks.index(user_stories_heading)
            if tech_index >= user_stories_index:
                errors.append("[X] Technical Specifications must appear before User Stories section")
            else:
                checks_passed.append("[C] Technical Specifications must appear before User Stories section")
    
        # Find Backend Requirements heading3
        backend_heading = None
        for block in page_blocks[tech_index:]:
            if block.get("type") == "heading3" and "backend requirements" in block.get("content", "").lower():
                backend_heading = block
                break
    
        if not backend_heading:
            errors.append("[X] Backend Requirements heading_3 not found")
        else:
            checks_passed.append("[C] Backend Requirements heading_3 found")
    
        backend_index = page_blocks.index(backend_heading)
    
        # Verify paragraph with concurrent users
        para_found = False
        for block in page_blocks[backend_index + 1:backend_index + 5]:
            if block.get("type") == "paragraph":
                content = block.get("content", "")
                if "10,000 concurrent users" in content and "99.9% uptime" in content:
                    para_found = True
                    break
    
        if not para_found:
            errors.append("[X] Paragraph with concurrent users and uptime not found")
        else:
            checks_passed.append("[C] Paragraph with concurrent users and uptime found")
    
        # Verify three todos
        todos = []
        for block in page_blocks[backend_index:]:
            if block.get("type") == "todo":
                todos.append(block)
            elif block.get("type") in ["heading2", "divider"]:
                break
            if len(todos) >= 3:
                break
    
        if len(todos) < 3:
            errors.append(f"[X] Expected 3 todos, found {len(todos)}")
        else:
            checks_passed.append(f"[C] Found 3 todos as expected")
    
        expected_todos = ["Redis caching", "database replication", "DDoS protection"]
        for i, expected in enumerate(expected_todos):
            if expected.lower() not in todos[i].get("content", "").lower():
                errors.append(f"[X] Todo {i+1} should mention {expected}")
            else:
                checks_passed.append(f"[C] Todo {i+1} should mention {expected}")
    
        # Find blue callout with performance baseline
        callout_found = False
        for block in page_blocks[backend_index:]:
            if block.get("type") == "callout":
                bg = block.get("properties", {}).get("backgroundColor", "").lower()
                content = block.get("content", "")
                if "blue" in bg and "200ms" in content and "95%" in content:
                    callout_found = True
                    break
    
        if not callout_found:
            errors.append("[X] Blue callout with performance baseline not found")
        else:
            checks_passed.append("[C] Blue callout with performance baseline found")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_product_requirements_technical_requirements(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Overview - Technical Requirements section insertion."""
    errors: list[str] = []
    checks_passed: list[str] = []

    
    
    try:
        pr_page = _find_page_by_title(final_state_backend, "Comprehensive Product Requirements Document")
        if not pr_page:
            errors.append("[X] Comprehensive Product Requirements Document page not found")
        else:
            checks_passed.append("[C] Comprehensive Product Requirements Document page found")
    
        page_blocks = sorted(_get_blocks_for_page(final_state_backend, pr_page.get("_id")), key=lambda b: b.get("order", 0))
    
        # Find Overview - Part 2 and Part 3 headings
        part2_heading = None
        part3_heading = None
        tech_req_heading = None
    
        for block in page_blocks:
            if block.get("type") == "heading3":
                content = block.get("content", "")
                if "Overview - Part 2" in content:
                    part2_heading = block
                elif "Overview - Part 3" in content:
                    part3_heading = block
                elif "Overview - Technical Requirements" in content:
                    tech_req_heading = block
    
        if not part2_heading or not part3_heading:
            errors.append("[X] Overview - Part 2 or Part 3 heading not found")
        else:
            checks_passed.append("[C] Overview - Part 2 or Part 3 heading found")
    
        if not tech_req_heading:
            errors.append("[X] Overview - Technical Requirements heading_3 not found")
        else:
            checks_passed.append("[C] Overview - Technical Requirements heading_3 found")
    
        # Verify positioning
        part2_index = page_blocks.index(part2_heading)
        tech_req_index = page_blocks.index(tech_req_heading)
        part3_index = page_blocks.index(part3_heading)
    
        if not (part2_index < tech_req_index < part3_index):
            errors.append("[X] Technical Requirements not positioned correctly between Part 2 and Part 3")
        else:
            checks_passed.append("[C] Technical Requirements positioned correctly between Part 2 and Part 3")
    
        # Verify paragraph after tech req heading
        if tech_req_index + 1 >= len(page_blocks) or page_blocks[tech_req_index + 1].get("type") != "paragraph":
            errors.append("[X] Paragraph not found after Technical Requirements heading")
        else:
            checks_passed.append("[C] Paragraph found after Technical Requirements heading")
    
        para_content = page_blocks[tech_req_index + 1].get("content", "")
        if "technical specifications and constraints" not in para_content.lower():
            errors.append("[X] Paragraph content incorrect")
        else:
            checks_passed.append("[C] Paragraph content incorrect")
    
        # Verify three bullets
        bullets = []
        for block in page_blocks[tech_req_index + 2:]:
            if block.get("type") == "bulletedList":
                bullets.append(block)
            elif block.get("type") in ["heading2", "heading3"]:
                break
            if len(bullets) >= 3:
                break
    
        if len(bullets) < 3:
            errors.append(f"[X] Expected 3 bulleted items, found {len(bullets)}")
        else:
            checks_passed.append(f"[C] Found 3 bulleted items as expected")
    
        required_terms = ["10,000 concurrent users", "encryption", "200ms"]
        for i, term in enumerate(required_terms):
            if term.lower() not in bullets[i].get("content", "").lower():
                errors.append(f"[X] Bullet {i+1} should mention {term}")
            else:
                checks_passed.append(f"[C] Bullet {i+1} should mention {term}")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_team_performance_report_meeting_analysis(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Team Performance Report with meeting analysis."""
    errors: list[str] = []
    checks_passed: list[str] = []

    
    # Find Meeting Notes
    try:
        meeting_notes = _find_page_by_title(final_state_backend, "Meeting Notes")
        if not meeting_notes:
            errors.append("[X] Meeting Notes page not found")
        else:
            checks_passed.append("[C] Meeting Notes page found")

        meeting_notes_id = meeting_notes.get("_id")

        # Find all sub-pages of Meeting Notes
        meeting_pages = _get_child_pages(final_state_backend, meeting_notes_id)

        if not meeting_pages:
            errors.append("[X] No meeting sub-pages found")
        else:
            checks_passed.append("[C] meeting sub-pages found")

        # Find Team Performance Report page
        report_page = _find_page_by_title_and_parent(final_state_backend, "📊 Team Performance Report", meeting_notes_id)
        if not report_page:
            errors.append("[X] Team Performance Report page not found under Meeting Notes")
        else:
            checks_passed.append("[C] Team Performance Report page found under Meeting Notes")
    
        # Exclude the report page from meeting pages to analyze
        report_page_id = report_page.get("_id")
        meeting_pages = [p for p in meeting_pages if p.get("_id") != report_page_id]
    
        if not meeting_pages:
            errors.append("[X] No meeting sub-pages found (excluding report page)")
        else:
            checks_passed.append("[C] meeting sub-pages found (excluding report page)")
    
        report_blocks = sorted(_get_blocks_for_page(final_state_backend, report_page.get("_id")), key=lambda b: b.get("order", 0))
    
        # Verify heading1
        if not report_blocks or report_blocks[0].get("type") != "heading1":
            errors.append("[X] First block is not heading1")
        else:
            checks_passed.append("[C] First block is heading1")
        if report_blocks[0].get("content") != "📊 Team Performance Report":
            errors.append("[X] First heading incorrect")
        else:
            checks_passed.append("[C] First heading incorrect")
    
        # Find Meeting Analysis heading
        analysis_heading = None
        for block in report_blocks:
            if block.get("type") == "heading2" and "meeting analysis" in block.get("content", "").lower():
                analysis_heading = block
                break
    
        if not analysis_heading:
            errors.append("[X] Meeting Analysis heading_2 not found")
        else:
            checks_passed.append("[C] Meeting Analysis heading_2 found")
    
        # Verify each meeting page has a heading3 with icon
        heading3_blocks = [b for b in report_blocks if b.get("type") == "heading3"]
    
        for meeting_page in meeting_pages:
            meeting_title = meeting_page.get("title", "")
            meeting_icon = meeting_page.get("icon", "")
        
            # Find matching heading3
            matching_h3 = None
            for h3 in heading3_blocks:
                content = h3.get("content", "")
                if meeting_title in content and "Summary" in content:
                    if meeting_icon and meeting_icon in content:
                        matching_h3 = h3
                        break
        
            if not matching_h3:
                errors.append(f"[X] Missing heading3 for meeting '{meeting_title}'")
            else:
                checks_passed.append(f"[C] has heading3 for meeting '{meeting_title}'")
        
            # Get blocks for this meeting to count types
            meeting_blocks = _get_blocks_for_page(final_state_backend, meeting_page.get("_id"))
        
            headings = sum(1 for b in meeting_blocks if b.get("type") in ["heading1", "heading2", "heading3"])
            todos = sum(1 for b in meeting_blocks if b.get("type") == "todo")
            discussion = sum(1 for b in meeting_blocks if b.get("type") in ["paragraph", "bulletedList"])
        
            # Find paragraph after heading3 with breakdown
            h3_index = report_blocks.index(matching_h3)
            breakdown_found = False
            for block in report_blocks[h3_index + 1:h3_index + 5]:
                if block.get("type") == "paragraph":
                    content = block.get("content", "")
                    if "Content breakdown:" in content and str(headings) in content and str(todos) in content:
                        breakdown_found = True
                        break
        
            if not breakdown_found:
                errors.append(f"[X] Content breakdown not found for '{meeting_title}'")
            else:
                checks_passed.append(f"[C] Content breakdown found for '{meeting_title}'")
    
        # Find Action Items Tracker heading
        tracker_heading = None
        for block in report_blocks:
            if block.get("type") == "heading2" and "action items tracker" in block.get("content", "").lower():
                tracker_heading = block
                break
    
        if not tracker_heading:
            errors.append("[X] Action Items Tracker heading_2 not found")
        else:
            checks_passed.append("[C] Action Items Tracker heading_2 found")
    
        # Count all todos across all meeting pages
        all_todos = []
        for meeting_page in meeting_pages:
            meeting_blocks = _get_blocks_for_page(final_state_backend, meeting_page.get("_id"))
            meeting_todos = [b for b in meeting_blocks if b.get("type") == "todo"]
            for todo in meeting_todos:
                all_todos.append((meeting_page.get("title", ""), todo))
    
        # Verify numbered list with todos
        tracker_index = report_blocks.index(tracker_heading)
        numbered_lists = []
        for block in report_blocks[tracker_index + 1:]:
            if block.get("type") == "numberedList":
                numbered_lists.append(block)
            elif block.get("type") in ["heading2", "callout"]:
                break
    
        if len(numbered_lists) < len(all_todos):
            errors.append(f"[X] Expected at least {len(all_todos)} numbered items for todos")
        else:
            checks_passed.append(f"[C] Expected at least {len(all_todos)} numbered items for todos")
    
        # Calculate completion rate
        completed = sum(1 for _, todo in all_todos if todo.get("properties", {}).get("checked"))
        total = len(all_todos)
        rate = int((completed / total) * 100) if total > 0 else 0
    
        # Find accountability callout
        callout_found = False
        for block in report_blocks[tracker_index:]:
            if block.get("type") == "callout":
                bg = block.get("properties", {}).get("backgroundColor", "").lower()
                icon = block.get("properties", {}).get("icon", "")
                content = block.get("content", "")
                if "gray" in bg and icon == "📊" and "Team accountability score:" in content:
                    if str(rate) in content and str(completed) in content and str(total) in content:
                        callout_found = True
                        break
    
        if not callout_found:
            errors.append("[X] Gray callout with accountability score not found")
        else:
            checks_passed.append("[C] Gray callout with accountability score found")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_development_resources_hub_creation(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Development Resources Hub page creation."""
    errors: list[str] = []
    checks_passed: list[str] = []

    
    # Find Project Documentation
    try:
        proj_doc = _find_page_by_title(final_state_backend, "Project Documentation")
        if not proj_doc:
            errors.append("[X] Project Documentation page not found")
        else:
            checks_passed.append("[C] Project Documentation page found")

        # Find Development Resources Hub
        hub_page = _find_page_by_title_and_parent(final_state_backend, "🔗 Development Resources Hub", proj_doc.get("_id"))
        if not hub_page:
            errors.append("[X] Development Resources Hub not found as child of Project Documentation")
        else:
            checks_passed.append("[C] Development Resources Hub found as child of Project Documentation")
    
        hub_blocks = sorted(_get_blocks_for_page(final_state_backend, hub_page.get("_id")), key=lambda b: b.get("order", 0))
    
        # Verify heading1
        if not hub_blocks or hub_blocks[0].get("type") != "heading1":
            errors.append("[X] First block is not heading1")
        else:
            checks_passed.append("[C] First block is heading1")
        if hub_blocks[0].get("content") != "🔗 Development Resources Hub":
            errors.append("[X] First heading incorrect")
        else:
            checks_passed.append("[C] First heading incorrect")
    
        # Verify intro paragraph
        if len(hub_blocks) < 2 or hub_blocks[1].get("type") != "paragraph":
            errors.append("[X] Intro paragraph not found")
        else:
            checks_passed.append("[C] Intro paragraph found")
        if "Centralized collection" not in hub_blocks[1].get("content", ""):
            errors.append("[X] Intro paragraph text incorrect")
        else:
            checks_passed.append("[C] Intro paragraph text incorrect")
    
        # Find Internal Documentation heading
        internal_heading = None
        for block in hub_blocks:
            if block.get("type") == "heading2" and "internal documentation" in block.get("content", "").lower():
                internal_heading = block
                break
    
        if not internal_heading:
            errors.append("[X] Internal Documentation heading_2 not found")
        else:
            checks_passed.append("[C] Internal Documentation heading_2 found")
    
        # Verify image from Design System
        design_system = _find_page_by_title(final_state_backend, "Design System")
        image_found = False
    
        if design_system:
            for block in hub_blocks:
                if block.get("type") == "image":
                    caption = block.get("properties", {}).get("caption", "")
                    if "design system reference" in caption.lower():
                        image_found = True
                        break
    
        if not image_found:
            errors.append("[X] Image with Design System caption not found")
        else:
            checks_passed.append("[C] Image with Design System caption found")
    
        # Verify three bookmarks
        bookmarks = [b for b in hub_blocks if b.get("type") == "bookmark"]
    
        required_bookmarks = [
            ("Engineering Wiki", "acme-corp.notion.site/engineering-wiki"),
            ("API Documentation", "acme-corp.notion.site/api-docs"),
            ("Company Handbook", "acme-corp.notion.site/company-handbook")
        ]
    
        for title, url_part in required_bookmarks:
            bookmark_found = False
            for bookmark in bookmarks:
                content = bookmark.get("content", "")
                url = bookmark.get("properties", {}).get("url", "")
                if title in content and url_part in url:
                    bookmark_found = True
                    break
        
            if not bookmark_found:
                errors.append(f"[X] Bookmark '{title}' not found")
            else:
                checks_passed.append(f"[C] Bookmark '{title}' found")
    
        # Find External Resources heading
        external_heading = None
        for block in hub_blocks:
            if block.get("type") == "heading2" and "external resources" in block.get("content", "").lower():
                external_heading = block
                break
    
        if not external_heading:
            errors.append("[X] External Resources heading_2 not found")
        else:
            checks_passed.append("[C] External Resources heading_2 found")
    
        # Find Important Guidelines heading
        guidelines_heading = None
        for block in hub_blocks:
            if block.get("type") == "heading2" and "important guidelines" in block.get("content", "").lower():
                guidelines_heading = block
                break
    
        if not guidelines_heading:
            errors.append("[X] Important Guidelines heading_2 not found")
        else:
            checks_passed.append("[C] Important Guidelines heading_2 found")
    
        # Verify callouts with yellow or red background
        guidelines_index = hub_blocks.index(guidelines_heading)
        callouts_after = []
        for block in hub_blocks[guidelines_index + 1:]:
            if block.get("type") == "callout":
                bg = block.get("properties", {}).get("backgroundColor", "").lower()
                if "yellow" in bg or "red" in bg:
                    callouts_after.append(block)
    
        if not callouts_after:
            errors.append("[X] No yellow or red callouts found in Important Guidelines section")
        else:
            checks_passed.append("[C] yellow or red callouts found in Important Guidelines section")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_workspace_audit_report_creation(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Workspace Audit Report at root level."""
    errors: list[str] = []
    checks_passed: list[str] = []

    
    # Find Workspace Audit Report page (no parent = root level)
    try:
        audit_page = _find_root_page_by_title(final_state_backend, "🔄 Workspace Audit Report")
        if not audit_page:
            errors.append("[X] Workspace Audit Report page not found at root level")
        else:
            checks_passed.append("[C] Workspace Audit Report page found at root level")

        audit_blocks = sorted(_get_blocks_for_page(final_state_backend, audit_page.get("_id")), key=lambda b: b.get("order", 0))

        # Verify heading1
        if not audit_blocks or audit_blocks[0].get("type") != "heading1":
            errors.append("[X] First block is not heading1")
        else:
            checks_passed.append("[C] First block is heading1")
        if audit_blocks[0].get("content") != "🔄 Workspace Audit Report":
            errors.append("[X] First heading incorrect")
        else:
            checks_passed.append("[C] First heading incorrect")

        # Find Page Statistics heading
        stats_heading = None
        for block in audit_blocks:
            if block.get("type") == "heading2" and "page statistics" in block.get("content", "").lower():
                stats_heading = block
                break

        if not stats_heading:
            errors.append("[X] Page Statistics heading_2 not found")
        else:
            checks_passed.append("[C] Page Statistics heading_2 found")

        # Calculate actual statistics using query-level filter
        workspace_pages = _get_workspace_pages(final_state_backend, "workspace-1")
        total_pages = len(workspace_pages)
        favorited = sum(1 for p in workspace_pages if p.get("isFavorite"))
        archived = sum(1 for p in workspace_pages if p.get("isArchived"))
        published = sum(1 for p in workspace_pages if p.get("sharingMetadata", {}).get("public"))
        with_children = sum(1 for p in workspace_pages if any(child.get("parentId") == p.get("_id") for child in workspace_pages))
    
        # Find numbered list with statistics
        stats_index = audit_blocks.index(stats_heading)
        numbered_lists = []
        for block in audit_blocks[stats_index + 1:]:
            if block.get("type") == "numberedList":
                numbered_lists.append(block)
            elif block.get("type") in ["heading2"]:
                break
            if len(numbered_lists) >= 5:
                break
    
        if len(numbered_lists) < 5:
            errors.append(f"[X] Expected 5 statistics items, found {len(numbered_lists)}")
        else:
            checks_passed.append(f"[C] Found 5 statistics items as expected")
    
        # Verify statistics are present (not checking exact values due to variability)
        required_terms = ["Total pages:", "Favorited pages:", "Archived pages:", "Published pages:", "Pages with sub-pages:"]
        for i, term in enumerate(required_terms):
            if term not in numbered_lists[i].get("content", ""):
                errors.append(f"[X] Statistic {i+1} should contain '{term}'")
            else:
                checks_passed.append(f"[C] Statistic {i+1} should contain '{term}'")
    
        # Find Most Complex Pages heading
        complex_heading = None
        for block in audit_blocks:
            if block.get("type") == "heading2" and "most complex pages" in block.get("content", "").lower():
                complex_heading = block
                break
    
        if not complex_heading:
            errors.append("[X] Most Complex Pages heading_2 not found")
        else:
            checks_passed.append("[C] Most Complex Pages heading_2 found")
    
        # Find Content by Creator heading
        creator_heading = None
        for block in audit_blocks:
            if block.get("type") == "heading2" and "content by creator" in block.get("content", "").lower():
                creator_heading = block
                break
    
        if not creator_heading:
            errors.append("[X] Content by Creator heading_2 not found")
        else:
            checks_passed.append("[C] Content by Creator heading_2 found")
    
        # Find Recent Activity heading with orange callout
        activity_heading = None
        for block in audit_blocks:
            if block.get("type") == "heading2" and "recent activity" in block.get("content", "").lower():
                activity_heading = block
                break
    
        if not activity_heading:
            errors.append("[X] Recent Activity heading_2 not found")
        else:
            checks_passed.append("[C] Recent Activity heading_2 found")
    
        activity_index = audit_blocks.index(activity_heading)
        callout_found = False
        for block in audit_blocks[activity_index + 1:activity_index + 5]:
            if block.get("type") == "callout":
                bg = block.get("properties", {}).get("backgroundColor", "").lower()
                if "orange" in bg and block.get("properties", {}).get("icon") == "🔔":
                    callout_found = True
                    break
    
        if not callout_found:
            errors.append("[X] Orange callout with bell icon not found under Recent Activity")
        else:
            checks_passed.append("[C] Orange callout with bell icon found under Recent Activity")
    
        # Find Maintenance Required heading
        maintenance_heading = None
        for block in audit_blocks:
            if block.get("type") == "heading2" and "maintenance required" in block.get("content", "").lower():
                maintenance_heading = block
                break
    
        if not maintenance_heading:
            errors.append("[X] Maintenance Required heading_2 not found")
        else:
            checks_passed.append("[C] Maintenance Required heading_2 found")
    
        # Verify archived pages listed as todos
        archived_pages = [p for p in workspace_pages if p.get("isArchived")]
        maintenance_index = audit_blocks.index(maintenance_heading)
        todos_after = [b for b in audit_blocks[maintenance_index + 1:] if b.get("type") == "todo"]
    
        if len(archived_pages) > 0 and len(todos_after) < len(archived_pages):
            errors.append(f"[X] Expected at least {len(archived_pages)} todos for archived pages")
        else:
            checks_passed.append(f"[C] Expected at least {len(archived_pages)} todos for archived pages")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_api_documentation_versioning_2(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate API Documentation versioning system."""
    errors: list[str] = []
    checks_passed: list[str] = []

    
    
    # Find API Documentation page
    try:
        api_page = _find_page_by_title(final_state_backend, "API Documentation")
        if not api_page:
            errors.append("[X] API Documentation page not found")
        else:
            checks_passed.append("[C] API Documentation page found")
    
        page_blocks = sorted(_get_blocks_for_page(final_state_backend, api_page.get("_id")), key=lambda b: b.get("order", 0))
    
        # Find Version Control heading (should be near top)
        version_heading = None
        version_index = -1
        for i, block in enumerate(page_blocks[:10]):  # Check first 10 blocks
            if block.get("type") == "heading2" and "version control" in block.get("content", "").lower():
                version_heading = block
                version_index = i
                break
    
        if not version_heading:
            errors.append("[X] Version Control heading_2 not found at top of page")
        else:
            checks_passed.append("[C] Version Control heading_2 found at top of page")
    
        # Verify yellow callout with version info
        callout_found = False
        if version_index + 1 < len(page_blocks):
            callout = page_blocks[version_index + 1]
            if callout.get("type") == "callout":
                bg = callout.get("properties", {}).get("backgroundColor", "").lower()
                content = callout.get("content", "")
                if "yellow" in bg and block.get("properties", {}).get("icon") == "⚠️" and "Current Version: v2.1.0" in content:
                    callout_found = True
    
        if not callout_found:
            errors.append("[X] Yellow callout with version v2.1.0 not found")
        else:
            checks_passed.append("[C] Yellow callout with version v2.1.0 found")
    
        # Find Recent Changes numbered list
        numbered_after_version = []
        for block in page_blocks[version_index:version_index + 10]:
            if block.get("type") == "numberedList":
                numbered_after_version.append(block)
            if len(numbered_after_version) >= 3:
                break
    
        if len(numbered_after_version) < 3:
            errors.append("[X] Expected 3 recent changes in numbered list")
        else:
            checks_passed.append("[C] Expected 3 recent changes in numbered list")
    
        # Verify change entries
        required_changes = ["WebSocket endpoints", "Deprecated legacy auth", "rate limiting"]
        for i, term in enumerate(required_changes):
            if term.lower() not in numbered_after_version[i].get("content", "").lower():
                errors.append(f"[X] Change {i+1} should mention {term}")
            else:
                checks_passed.append(f"[C] Change {i+1} should mention {term}")
    
        # Find existing code blocks and verify Example request paragraphs before them
        code_blocks = [b for b in page_blocks if b.get("type") == "code"]
    
        if not code_blocks:
            errors.append("[X] No code blocks found on page")
        else:
            checks_passed.append("[C] code blocks found on page")
    
        for code_block in code_blocks:
            code_index = page_blocks.index(code_block)
        
            # Check if there's an "Example request:" paragraph before it
            if code_index > 0:
                prev_block = page_blocks[code_index - 1]
                if prev_block.get("type") != "paragraph" or "Example request:" not in prev_block.get("content", ""):
                    errors.append("[X] Missing 'Example request:' paragraph before code block")
                else:
                    checks_passed.append("[C] has 'Example request:' paragraph before code block")
        
            # Check if there's a gray callout after it
            if code_index + 1 < len(page_blocks):
                next_block = page_blocks[code_index + 1]
                if next_block.get("type") == "callout":
                    bg = next_block.get("properties", {}).get("backgroundColor", "").lower()
                    content = next_block.get("content", "")
                    if "gray" in bg and code_block.get("properties", {}).get("icon") == "💡" and "Response format:" in content:
                        continue
                    else:
                        errors.append("[X] Gray callout after code block missing or incorrect")
                else:
                    errors.append("[X] Callout not found after code block")
    
        # Find Related Resources heading
        resources_heading = None
        for block in page_blocks:
            if block.get("type") == "heading2" and "related resources" in block.get("content", "").lower():
                resources_heading = block
                break
    
        if not resources_heading:
            errors.append("[X] Related Resources heading_2 not found")
        else:
            checks_passed.append("[C] Related Resources heading_2 found")
    
        resources_index = page_blocks.index(resources_heading)
    
        # Find two bookmarks
        bookmarks_after = []
        for block in page_blocks[resources_index + 1:]:
            if block.get("type") == "bookmark":
                bookmarks_after.append(block)
            elif block.get("type") in ["heading2", "divider"]:
                break
            if len(bookmarks_after) >= 2:
                break
    
        if len(bookmarks_after) < 2:
            errors.append("[X] Expected 2 bookmarks under Related Resources")
        else:
            checks_passed.append("[C] Expected 2 bookmarks under Related Resources")
    
        # Verify bookmark URLs
        required_urls = ["api.acme.com/swagger", "status.acme.com"]
        for url_part in required_urls:
            url_found = False
            for bookmark in bookmarks_after:
                url = bookmark.get("properties", {}).get("url", "")
                if url_part in url:
                    url_found = True
                    break
        
            if not url_found:
                errors.append(f"[X] Bookmark with URL containing '{url_part}' not found")
            else:
                checks_passed.append(f"[C] Bookmark with URL containing '{url_part}' found")
    
        # Find divider and quote at end
        quote_found = False
        for i, block in enumerate(page_blocks):
            if block.get("type") == "divider":
                if i + 1 < len(page_blocks):
                    next_block = page_blocks[i + 1]
                    if next_block.get("type") == "quote":
                        if "Good documentation is as important as good code" in next_block.get("content", ""):
                            quote_found = True
                            break
    
        if not quote_found:
            errors.append("[X] Divider and quote not found at end")
        else:
            checks_passed.append("[C] Divider and quote found at end")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_bug_analysis_report_creation(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Bug Analysis Report as child of Bug Tracker."""
    errors: list[str] = []
    checks_passed: list[str] = []

    
    # Find Bug Tracker page
    try:
        bug_tracker = _find_page_by_title(final_state_backend, "Bug Tracker")
        if not bug_tracker:
            errors.append("[X] Bug Tracker page not found")
        else:
            checks_passed.append("[C] Bug Tracker page found")

        # Get all blocks from Bug Tracker to analyze priorities
        tracker_blocks = _get_blocks_for_page(final_state_backend, bug_tracker.get("_id"))

        # Find Bug Analysis Report page
        report_page = _find_page_by_title_pattern_and_parent(final_state_backend, "bug analysis report", bug_tracker.get("_id"))
        if not report_page:
            errors.append("[X] Bug Analysis Report page not found as child of Bug Tracker")
        else:
            checks_passed.append("[C] Bug Analysis Report page found as child of Bug Tracker")
    
        report_blocks = sorted(_get_blocks_for_page(final_state_backend, report_page.get("_id")), key=lambda b: b.get("order", 0))
    
        # Verify heading1 with month/year
        if not report_blocks or report_blocks[0].get("type") != "heading1":
            errors.append("[X] First block is not heading1")
        else:
            checks_passed.append("[C] First block is heading1")
        if "🐛 Bug Analysis Report" not in report_blocks[0].get("content", ""):
            errors.append("[X] First heading should contain 'Bug Analysis Report'")
        else:
            checks_passed.append("[C] First heading should contain 'Bug Analysis Report'")
    
        # Find Executive Summary heading
        summary_heading = None
        for block in report_blocks:
            if block.get("type") == "heading2" and "executive summary" in block.get("content", "").lower():
                summary_heading = block
                break
    
        if not summary_heading:
            errors.append("[X] Executive Summary heading_2 not found")
        else:
            checks_passed.append("[C] Executive Summary heading_2 found")
    
        summary_index = report_blocks.index(summary_heading)
    
        # Verify summary paragraph with total and resolution rate
        summary_para_found = False
        for block in report_blocks[summary_index + 1:summary_index + 5]:
            if block.get("type") == "paragraph":
                content = block.get("content", "")
                if "Total bugs tracked:" in content and "Resolution rate:" in content:
                    summary_para_found = True
                    break
    
        if not summary_para_found:
            errors.append("[X] Summary paragraph with totals not found")
        else:
            checks_passed.append("[C] Summary paragraph with totals found")
    
        # Find priority analysis headings (Critical, Medium, Low)
        priority_headings = {}
        for block in report_blocks:
            if block.get("type") == "heading3":
                content = block.get("content", "")
                if "critical" in content.lower() and "priority analysis" in content.lower():
                    priority_headings["critical"] = block
                elif "medium" in content.lower() and "priority analysis" in content.lower():
                    priority_headings["medium"] = block
                elif "low" in content.lower() and "priority analysis" in content.lower():
                    priority_headings["low"] = block
    
        if len(priority_headings) < 3:
            errors.append(f"[X] Expected 3 priority analysis sections, found {len(priority_headings)}")
        else:
            checks_passed.append(f"[C] Found 3 priority analysis sections as expected")
    
        # Verify each priority has a bulleted list and callout
        for priority, heading in priority_headings.items():
            h_index = report_blocks.index(heading)
        
            # Find bulleted lists after heading
            bullets = []
            for block in report_blocks[h_index + 1:]:
                if block.get("type") == "bulletedList":
                    bullets.append(block)
                elif block.get("type") in ["heading2", "heading3"]:
                    break
        
            if len(bullets) < 3:
                errors.append(f"[X] {priority.capitalize()} priority should have at least 3 bulleted items")
            else:
                checks_passed.append(f"[C] {priority.capitalize()} priority should have at least 3 bulleted items")
        
            # Verify bullets contain expected terms
            required_terms = [f"Total {priority}", "Resolved:", "Pending:", "Resolution rate:"]
            bullets_text = " ".join([b.get("content", "") for b in bullets])
            for term in required_terms:
                if term.lower() not in bullets_text.lower():
                    errors.append(f"[X] {priority.capitalize()} priority missing '{term}' in bullets")
                else:
                    checks_passed.append(f"[C] {priority.capitalize()} priority has '{term}' in bullets")
        
            # Find callout with appropriate color
            callout_found = False
            for block in report_blocks[h_index + 1:]:
                if block.get("type") == "callout":
                    bg = block.get("properties", {}).get("backgroundColor", "").lower()
                
                    # Check color matches priority
                    if priority == "critical" and "red" in bg:
                        callout_found = True
                        break
                    elif priority == "medium" and "orange" in bg:
                        callout_found = True
                        break
                    elif priority == "low" and "gray" in bg:
                        callout_found = True
                        break
                elif block.get("type") in ["heading2", "heading3"]:
                    break
        
            if not callout_found:
                errors.append(f"[X] {priority.capitalize()} priority missing callout with correct color")
            else:
                checks_passed.append(f"[C] {priority.capitalize()} priority has callout with correct color")
    
        # Find Recommendations heading
        reco_heading = None
        for block in report_blocks:
            if block.get("type") == "heading2" and "recommendations" in block.get("content", "").lower():
                reco_heading = block
                break
    
        if not reco_heading:
            errors.append("[X] Recommendations heading_2 not found")
        else:
            checks_passed.append("[C] Recommendations heading_2 found")
    
        # Verify numbered list with recommendations
        reco_index = report_blocks.index(reco_heading)
        numbered_after = []
        for block in report_blocks[reco_index + 1:]:
            if block.get("type") == "numberedList":
                numbered_after.append(block)
            if len(numbered_after) >= 3:
                break
    
        if len(numbered_after) < 3:
            errors.append("[X] Expected at least 3 numbered recommendations")
        else:
            checks_passed.append("[C] Expected at least 3 numbered recommendations")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_sprint_planning_section_swap(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Sprint Planning section swap (Attendees <-> Sprint Goals)."""
    errors: list[str] = []
    checks_passed: list[str] = []

    
    # Find Sprint Planning - Jan 15
    try:
        sprint_page = _find_page_with_all_title_patterns(final_state_backend, ["sprint planning", "jan 15"])
    
        if not sprint_page:
            errors.append("[X] Sprint Planning - Jan 15 page not found")
        else:
            checks_passed.append("[C] Sprint Planning - Jan 15 page found")
    
        page_blocks = sorted(_get_blocks_for_page(final_state_backend, sprint_page.get("_id")), key=lambda b: b.get("order", 0))
    
        # Find section headings
        attendees_heading = None
        goals_heading = None
        timeline_heading = None
    
        for block in page_blocks:
            if block.get("type") == "heading2":
                content = block.get("content", "")
                if "attendees" in content.lower():
                    attendees_heading = block
                elif "sprint goals" in content.lower():
                    goals_heading = block
                elif "sprint timeline" in content.lower():
                    timeline_heading = block
    
        if not attendees_heading or not goals_heading:
            errors.append("[X] Attendees or Sprint Goals heading not found")
        else:
            checks_passed.append("[C] Attendees or Sprint Goals heading found")
    
        attendees_index = page_blocks.index(attendees_heading)
        goals_index = page_blocks.index(goals_heading)
    
        # Verify Sprint Goals now appears before Attendees (swapped)
        if goals_index >= attendees_index:
            errors.append("[X] Sprint Goals should appear before Attendees (sections should be swapped)")
        else:
            checks_passed.append("[C] Sprint Goals should appear before Attendees (sections should be swapped)")
    
        # Verify Sprint Timeline heading exists between them
        if not timeline_heading:
            errors.append("[X] Sprint Timeline heading_2 not found")
        else:
            checks_passed.append("[C] Sprint Timeline heading_2 found")
    
        timeline_index = page_blocks.index(timeline_heading)
    
        # Verify order: Goals -> Attendees -> Timeline or Goals -> Timeline -> something
        if not (goals_index < attendees_index):
            errors.append("[X] Section order incorrect after swap")
        else:
            checks_passed.append("[C] Section order incorrect after swap")
    
        # Verify three todos under Timeline heading
        timeline_todos = []
        for block in page_blocks[timeline_index + 1:]:
            if block.get("type") == "todo":
                timeline_todos.append(block)
            elif block.get("type") in ["heading2"]:
                break
            if len(timeline_todos) >= 3:
                break
    
        if len(timeline_todos) < 3:
            errors.append(f"[X] Expected 3 todos under Sprint Timeline, found {len(timeline_todos)}")
        else:
            checks_passed.append(f"[C] Found 3 todos under Sprint Timeline as expected")
    
        # Verify todo texts
        expected_todos = [
            "🗓️ Sprint start: January 16",
            "🏁 Sprint end: January 29",
            "👥 Daily standups: 10 AM EST"
        ]
    
        for i, expected in enumerate(expected_todos):
            if timeline_todos[i].get("content") != expected:
                errors.append(f"[X] Todo {i+1} text incorrect: expected '{expected}'")
            else:
                checks_passed.append(f"[C] Todo {i+1} text incorrect: expected '{expected}'")
            if timeline_todos[i].get("properties", {}).get("checked"):
                errors.append(f"[X] Todo {i+1} should be unchecked")
            else:
                checks_passed.append(f"[C] Todo {i+1} should be unchecked")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_team_retrospective_action_items_2(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate Team Retrospective action items task.

    Verification:
    - Divider added after "What went well" bullets
    - heading_3 "🎯 Action Items from Wins" exists after divider
    - Three specific unchecked todos exist
    - heading_2 "📈 Historical Win Tracking" at end with paragraph showing win count
    - Green callout with 🌟 icon at the end
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    # Find Team Retrospective page
    try:
        retro_page = _find_page_by_title(final_state_backend, "team retrospective")
        if not retro_page:
            errors.append("[X] Team Retrospective page not found")
        else:
            checks_passed.append("[C] Team Retrospective page found")

        page_blocks = sorted(
            _get_blocks_for_page(final_state_backend, retro_page.get("_id")),
            key=lambda b: b.get("order", 0)
        )

        # Find "What went well" heading
        what_went_well_index = -1
        for i, block in enumerate(page_blocks):
            if block.get("type") == "heading3" and "what went well" in block.get("content", "").lower():
                what_went_well_index = i
                break

        if what_went_well_index == -1:
            errors.append("[X] 'What went well' heading not found")
        else:
            checks_passed.append("[C] 'What went well' heading found")

        # Find the last bullet point in "What went well" section
        last_bullet_index = what_went_well_index
        for i in range(what_went_well_index + 1, len(page_blocks)):
            block = page_blocks[i]
            if block.get("type") == "bulletedList":
                last_bullet_index = i
            elif block.get("type") in ["heading2", "heading3"]:
                break

        # Check for divider after the last bullet
        divider_found = False
        divider_index = -1
        for i in range(last_bullet_index + 1, len(page_blocks)):
            if page_blocks[i].get("type") == "divider":
                divider_found = True
                divider_index = i
                break
            elif page_blocks[i].get("type") in ["heading2", "heading3"]:
                break

        if not divider_found:
            errors.append("[X] Divider not found after 'What went well' bullets")
        else:
            checks_passed.append("[C] Divider found after 'What went well' bullets")

        # Check for heading_3 "🎯 Action Items from Wins" after divider
        action_items_heading_found = False
        action_items_index = -1
        for i in range(divider_index + 1, min(divider_index + 5, len(page_blocks))):
            block = page_blocks[i]
            if block.get("type") == "heading3" and "action items from wins" in block.get("content", "").lower():
                action_items_heading_found = True
                action_items_index = i
                break

        if not action_items_heading_found:
            errors.append("[X] heading_3 '🎯 Action Items from Wins' not found after divider")
        else:
            checks_passed.append("[C] heading_3 '🎯 Action Items from Wins' found after divider")

        # Check for three specific unchecked todos
        expected_todos = [
            "document the new editor architecture",
            "share collaboration best practices",
            "create a case study"
        ]
        found_todos = 0
        for i in range(action_items_index + 1, len(page_blocks)):
            block = page_blocks[i]
            if block.get("type") == "todo":
                content = block.get("content", "").lower()
                for expected in expected_todos:
                    if expected in content:
                        if block.get("properties", {}).get("checked"):
                            errors.append(f"[X] Todo '{expected}' should be unchecked")
                        else:
                            checks_passed.append(f"[C] Todo '{expected}' should be unchecked")
                        found_todos += 1
                        break
            elif block.get("type") in ["heading2", "heading3"]:
                break

        if found_todos < 3:
            errors.append(f"[X] Expected 3 action item todos, found {found_todos}")
        else:
            checks_passed.append(f"[C] Found 3 action item todos as expected")

        # Check for heading_2 "📈 Historical Win Tracking"
        historical_heading_found = False
        historical_index = -1
        for i, block in enumerate(page_blocks):
            if block.get("type") == "heading2" and "historical win tracking" in block.get("content", "").lower():
                historical_heading_found = True
                historical_index = i
                break

        if not historical_heading_found:
            errors.append("[X] heading_2 '📈 Historical Win Tracking' not found")
        else:
            checks_passed.append("[C] heading_2 '📈 Historical Win Tracking' found")

        # Check for paragraph with "Total wins across all retrospectives"
        total_wins_found = False
        for i in range(historical_index + 1, len(page_blocks)):
            block = page_blocks[i]
            if block.get("type") == "paragraph" and "total wins" in block.get("content", "").lower():
                total_wins_found = True
                break
            elif block.get("type") in ["heading2"]:
                break

        if not total_wins_found:
            errors.append("[X] Paragraph with 'Total wins across all retrospectives' not found")
        else:
            checks_passed.append("[C] Paragraph with 'Total wins across all retrospectives' found")

        # Check for green callout with 🌟 icon at the end
        callout_found = False
        for block in reversed(page_blocks):
            if block.get("type") == "callout":
                props = block.get("properties", {})
                content = block.get("content", "")
                if "green" in props.get("backgroundColor", "") or props.get("icon") == "🌟":
                    if "celebrating wins" in content.lower() or "archive completed" in content.lower():
                        callout_found = True
                        break

        if not callout_found:
            errors.append("[X] Green callout with 🌟 icon not found at end")
        else:
            checks_passed.append("[C] Green callout with 🌟 icon found at end")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_design_system_child_page_restructure(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate Design System child page restructure.

    Verification:
    - 'Core Elements' page created with 📦 icon as child of Design System
    - 'Color Palette' and 'Typography' moved as children of Core Elements
    - 'UI Components' page created with 🧩 icon as child of Design System
    - 'Components' page moved as child of UI Components
    - heading2 '🗺️ Structure Overview' added to main Design System page
    - Numbered list with descriptions added
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    # Find Design System page
    try:
        design_system_page = _find_page_by_title_and_workspace(final_state_backend, "design system", "workspace-1")
        if not design_system_page:
            errors.append("[X] Design System page not found")
        else:
            checks_passed.append("[C] Design System page found")

        design_system_id = design_system_page.get("_id")

        # Check for 'Core Elements' page with 📦 icon as child of Design System
        core_elements_page = _find_page_by_title_pattern_and_parent(final_state_backend, "core elements", design_system_id)
        if not core_elements_page:
            errors.append("[X] 'Core Elements' page not found as child of Design System")
        else:
            checks_passed.append("[C] 'Core Elements' page found as child of Design System")

        if core_elements_page.get("icon") != "📦":
            errors.append("[X] 'Core Elements' page should have 📦 icon")
        else:
            checks_passed.append("[C] 'Core Elements' page should have 📦 icon")

        core_elements_id = core_elements_page.get("_id")

        # Check for 'Color Palette' and 'Typography' as children of Core Elements
        core_element_children = _get_child_pages(final_state_backend, core_elements_id)
        color_palette_found = any("color palette" in p.get("title", "").lower() for p in core_element_children)
        typography_found = any("typography" in p.get("title", "").lower() for p in core_element_children)

        if not color_palette_found:
            errors.append("[X] 'Color Palette' page not found as child of Core Elements")
        else:
            checks_passed.append("[C] 'Color Palette' page found as child of Core Elements")
        if not typography_found:
            errors.append("[X] 'Typography' page not found as child of Core Elements")
        else:
            checks_passed.append("[C] 'Typography' page found as child of Core Elements")

        # Check for 'UI Components' page with 🧩 icon as child of Design System
        ui_components_page = _find_page_by_title_pattern_and_parent(final_state_backend, "ui components", design_system_id)
        if not ui_components_page:
            errors.append("[X] 'UI Components' page not found as child of Design System")
        else:
            checks_passed.append("[C] 'UI Components' page found as child of Design System")

        if ui_components_page.get("icon") != "🧩":
            errors.append("[X] 'UI Components' page should have 🧩 icon")
        else:
            checks_passed.append("[C] 'UI Components' page should have 🧩 icon")

        ui_components_id = ui_components_page.get("_id")

        # Check for 'Components' as child of UI Components
        ui_component_children = _get_child_pages(final_state_backend, ui_components_id)
        components_found = any("components" in p.get("title", "").lower() for p in ui_component_children)

        if not components_found:
            errors.append("[X] 'Components' page not found as child of UI Components")
        else:
            checks_passed.append("[C] 'Components' page found as child of UI Components")

        # Check for heading2 '🗺️ Structure Overview' on main Design System page
        page_blocks = sorted(
            _get_blocks_for_page(final_state_backend, design_system_id),
            key=lambda b: b.get("order", 0)
        )

        structure_heading_found = False
        structure_heading_index = -1
        for i, block in enumerate(page_blocks):
            if block.get("type") == "heading2" and "structure overview" in block.get("content", "").lower():
                structure_heading_found = True
                structure_heading_index = i
                break

        if not structure_heading_found:
            errors.append("[X] heading2 '🗺️ Structure Overview' not found on Design System page")
        else:
            checks_passed.append("[C] heading2 '🗺️ Structure Overview' found on Design System page")

        # Check for numbered list after the heading
        numbered_items_found = 0
        for i in range(structure_heading_index + 1, len(page_blocks)):
            block = page_blocks[i]
            if block.get("type") == "numberedList":
                content = block.get("content", "").lower()
                if "core elements" in content or "ui components" in content:
                    numbered_items_found += 1
            elif block.get("type") in ["heading1", "heading2", "heading3"]:
                break

        if numbered_items_found < 2:
            errors.append(f"[X] Expected 2 numbered list items, found {numbered_items_found}")
        else:
            checks_passed.append(f"[C] Found 2 numbered list items as expected")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_standard_operating_procedure_creation(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate Standard Operating Procedure creation.

    Verification:
    - Page created with '📋' icon
    - heading_1 '📋 Standard Operating Procedure' exists
    - heading_2 '📚 Terminologies' with 3 bulleted items (SOP, KPI, SLA)
    - heading_2 '👥 Roles & Responsibilities' with 3 numbered items
    - heading_2 '🔧 Tools' with paragraph and 2 bookmark blocks
    - Two child pages: 'Onboarding Checklist' and 'Emergency Procedures'
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    # Find Standard Operating Procedure page
    try:
        sop_page = _find_page_by_title(final_state_backend, "standard operating procedure")
        if not sop_page:
            errors.append("[X] Standard Operating Procedure page not found")
        else:
            checks_passed.append("[C] Standard Operating Procedure page found")

        if sop_page.get("icon") != "📋":
            errors.append("[X] SOP page should have 📋 icon")
        else:
            checks_passed.append("[C] SOP page should have 📋 icon")

        sop_id = sop_page.get("_id")

        page_blocks = sorted(
            _get_blocks_for_page(final_state_backend, sop_id),
            key=lambda b: b.get("order", 0)
        )

        # Check for heading_1 '📋 Standard Operating Procedure'
        heading1_found = False
        for block in page_blocks:
            if block.get("type") == "heading1" and "standard operating procedure" in block.get("content", "").lower():
                heading1_found = True
                break

        if not heading1_found:
            errors.append("[X] heading_1 '📋 Standard Operating Procedure' not found")
        else:
            checks_passed.append("[C] heading_1 '📋 Standard Operating Procedure' found")

        # Check for heading_2 '📚 Terminologies' with 3 bulleted items
        terminologies_index = -1
        for i, block in enumerate(page_blocks):
            if block.get("type") == "heading2" and "terminologies" in block.get("content", "").lower():
                terminologies_index = i
                break

        if terminologies_index == -1:
            errors.append("[X] heading_2 '📚 Terminologies' not found")
        else:
            checks_passed.append("[C] heading_2 '📚 Terminologies' found")

        # Count bulleted items with SOP, KPI, SLA
        terminology_items = {"sop": False, "kpi": False, "sla": False}
        for i in range(terminologies_index + 1, len(page_blocks)):
            block = page_blocks[i]
            if block.get("type") == "bulletedList":
                content = block.get("content", "").lower()
                if "sop" in content:
                    terminology_items["sop"] = True
                if "kpi" in content:
                    terminology_items["kpi"] = True
                if "sla" in content:
                    terminology_items["sla"] = True
            elif block.get("type") in ["heading2"]:
                break

        if not all(terminology_items.values()):
            missing = [k for k, v in terminology_items.items() if not v]
            errors.append(f"[X] Missing terminology items: {missing}")
        else:
            checks_passed.append(f"[C] has terminology items: {has}")

        # Check for heading_2 '👥 Roles & Responsibilities' with 3 numbered items
        roles_index = -1
        for i, block in enumerate(page_blocks):
            if block.get("type") == "heading2" and "roles" in block.get("content", "").lower():
                roles_index = i
                break

        if roles_index == -1:
            errors.append("[X] heading_2 '👥 Roles & Responsibilities' not found")
        else:
            checks_passed.append("[C] heading_2 '👥 Roles & Responsibilities' found")

        # Count numbered items with Project Manager, Tech Lead, QA Engineer
        role_items = {"project manager": False, "tech lead": False, "qa engineer": False}
        for i in range(roles_index + 1, len(page_blocks)):
            block = page_blocks[i]
            if block.get("type") == "numberedList":
                content = block.get("content", "").lower()
                if "project manager" in content:
                    role_items["project manager"] = True
                if "tech lead" in content:
                    role_items["tech lead"] = True
                if "qa engineer" in content:
                    role_items["qa engineer"] = True
            elif block.get("type") in ["heading2"]:
                break

        if not all(role_items.values()):
            missing = [k for k, v in role_items.items() if not v]
            errors.append(f"[X] Missing role items: {missing}")
        else:
            checks_passed.append(f"[C] has role items: {has}")

        # Check for heading_2 '🔧 Tools' with paragraph and 2 bookmarks
        tools_index = -1
        for i, block in enumerate(page_blocks):
            if block.get("type") == "heading2" and "tools" in block.get("content", "").lower():
                tools_index = i
                break

        if tools_index == -1:
            errors.append("[X] heading_2 '🔧 Tools' not found")
        else:
            checks_passed.append("[C] heading_2 '🔧 Tools' found")

        # Check for paragraph and bookmarks
        paragraph_found = False
        bookmark_count = 0
        notion_bookmark = False
        figma_bookmark = False

        for i in range(tools_index + 1, len(page_blocks)):
            block = page_blocks[i]
            if block.get("type") == "paragraph":
                paragraph_found = True
            elif block.get("type") == "bookmark":
                bookmark_count += 1
                url = block.get("properties", {}).get("url", "").lower()
                if "notion" in url:
                    notion_bookmark = True
                if "figma" in url:
                    figma_bookmark = True
            elif block.get("type") in ["heading2"]:
                break

        if not paragraph_found:
            errors.append("[X] Paragraph not found under Tools section")
        else:
            checks_passed.append("[C] Paragraph found under Tools section")
        if bookmark_count < 2:
            errors.append(f"[X] Expected 2 bookmark blocks, found {bookmark_count}")
        else:
            checks_passed.append(f"[C] Found 2 bookmark blocks as expected")
        if not notion_bookmark:
            errors.append("[X] Bookmark for notion.so not found")
        else:
            checks_passed.append("[C] Bookmark for notion.so found")
        if not figma_bookmark:
            errors.append("[X] Bookmark for figma.com not found")
        else:
            checks_passed.append("[C] Bookmark for figma.com found")

        # Check for two child pages
        child_pages = _get_child_pages(final_state_backend, sop_id)
        onboarding_found = False
        emergency_found = False

        for page in child_pages:
            title = page.get("title", "").lower()
            if "onboarding checklist" in title:
                onboarding_found = True
            if "emergency procedures" in title:
                emergency_found = True

        if not onboarding_found:
            errors.append("[X] Child page 'Onboarding Checklist' not found")
        else:
            checks_passed.append("[C] Child page 'Onboarding Checklist' found")
        if not emergency_found:
            errors.append("[X] Child page 'Emergency Procedures' not found")
        else:
            checks_passed.append("[C] Child page 'Emergency Procedures' found")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_weekly_standup_performance_tracking(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate Weekly Standup Template performance tracking transformation.

    Verification:
    - heading_2 '📈 Weekly Performance Metrics' after main heading
    - Image block with correct URL and caption
    - Bulleted list with tasks completed, total tasks, completion rate
    - heading_2 '🔮 Next Week Planning' after existing todos
    - Three unchecked todos for next week
    - Divider at the end
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    # Find Weekly Standup Template page
    try:
        standup_page = _find_page_by_title(final_state_backend, "weekly standup template")
        if not standup_page:
            errors.append("[X] Weekly Standup Template page not found")
        else:
            checks_passed.append("[C] Weekly Standup Template page found")

        page_blocks = sorted(
            _get_blocks_for_page(final_state_backend, standup_page.get("_id")),
            key=lambda b: b.get("order", 0)
        )

        # Find heading_2 '📈 Weekly Performance Metrics'
        metrics_heading_index = -1
        for i, block in enumerate(page_blocks):
            if block.get("type") == "heading2" and "performance metrics" in block.get("content", "").lower():
                metrics_heading_index = i
                break

        if metrics_heading_index == -1:
            errors.append("[X] heading_2 '📈 Weekly Performance Metrics' not found")
        else:
            checks_passed.append("[C] heading_2 '📈 Weekly Performance Metrics' found")

        # Check for image block after metrics heading
        image_found = False
        for i in range(metrics_heading_index + 1, len(page_blocks)):
            block = page_blocks[i]
            if block.get("type") == "image":
                props = block.get("properties", {})
                url = props.get("url", "")
                if "standup-metrics" in url or "charts.example.com" in url:
                    image_found = True
                    break
            elif block.get("type") in ["heading2"]:
                break

        if not image_found:
            errors.append("[X] Image block with metrics URL not found")
        else:
            checks_passed.append("[C] Image block with metrics URL found")

        # Check for bulleted list with metrics
        metrics_bullets = {"completed": False, "total": False, "rate": False}
        for i in range(metrics_heading_index + 1, len(page_blocks)):
            block = page_blocks[i]
            if block.get("type") == "bulletedList":
                content = block.get("content", "").lower()
                if "completed" in content:
                    metrics_bullets["completed"] = True
                if "total" in content:
                    metrics_bullets["total"] = True
                if "rate" in content or "percentage" in content:
                    metrics_bullets["rate"] = True
            elif block.get("type") in ["heading2"]:
                break

        if not all(metrics_bullets.values()):
            missing = [k for k, v in metrics_bullets.items() if not v]
            errors.append(f"[X] Missing metrics bullets: {missing}")
        else:
            checks_passed.append(f"[C] has metrics bullets: {has}")

        # Check for heading_2 '🔮 Next Week Planning'
        planning_heading_index = -1
        for i, block in enumerate(page_blocks):
            if block.get("type") == "heading2" and "next week planning" in block.get("content", "").lower():
                planning_heading_index = i
                break

        if planning_heading_index == -1:
            errors.append("[X] heading_2 '🔮 Next Week Planning' not found")
        else:
            checks_passed.append("[C] heading_2 '🔮 Next Week Planning' found")

        # Check for three unchecked todos under planning
        planning_todos = []
        expected_planning = ["architecture review", "user interviews", "performance metrics"]

        for i in range(planning_heading_index + 1, len(page_blocks)):
            block = page_blocks[i]
            if block.get("type") == "todo":
                if block.get("properties", {}).get("checked"):
                    errors.append("[X] Next week planning todos should be unchecked")
                else:
                    checks_passed.append("[C] Next week planning todos should be unchecked")
                content = block.get("content", "").lower()
                for expected in expected_planning:
                    if expected in content:
                        planning_todos.append(expected)
                        break
            elif block.get("type") in ["heading2", "divider"]:
                break

        if len(planning_todos) < 3:
            errors.append(f"[X] Expected 3 planning todos, found {len(planning_todos)}")
        else:
            checks_passed.append(f"[C] Found 3 planning todos as expected")

        # Check for divider at the end
        divider_found = False
        for block in reversed(page_blocks):
            if block.get("type") == "divider":
                divider_found = True
                break
            elif block.get("type") in ["heading1", "heading2"]:
                break

        if not divider_found:
            errors.append("[X] Divider not found at the end")
        else:
            checks_passed.append("[C] Divider found at the end")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_meeting_notes_index_creation(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """
    Validate Meeting Notes index creation.

    Verification:
    - heading_1 '📅 Meeting Index' is the first block
    - heading_2 '📊 Meeting Summary Statistics'
    - Blue callout with 📈 icon showing total meetings
    - heading_2 '🗓️ Recent Meetings' with numbered list
    - Divider followed by heading_3 '🔍 Quick Links'
    - Bookmark blocks for each meeting page
    """
    errors: list[str] = []
    checks_passed: list[str] = []

    # Find Meeting Notes page (parent page, not a child)
    # First try to find at root level, then fall back to any match
    try:
        meeting_notes_page = _find_root_page_by_title(final_state_backend, "Meeting Notes")
        if not meeting_notes_page:
            meeting_notes_page = _find_page_by_title(final_state_backend, "Meeting Notes")
        if not meeting_notes_page:
            errors.append("[X] Meeting Notes page not found")
        else:
            checks_passed.append("[C] Meeting Notes page found")

        meeting_notes_id = meeting_notes_page.get("_id")

        page_blocks = sorted(
            _get_blocks_for_page(final_state_backend, meeting_notes_id),
            key=lambda b: b.get("order", 0)
        )

        if not page_blocks:
            errors.append("[X] No blocks found on Meeting Notes page")
        else:
            checks_passed.append("[C] blocks found on Meeting Notes page")

        # Check heading_1 '📅 Meeting Index' is first
        first_block = page_blocks[0]
        if first_block.get("type") != "heading1" or "meeting index" not in first_block.get("content", "").lower():
            errors.append("[X] heading_1 '📅 Meeting Index' should be the first block")
        else:
            checks_passed.append("[C] heading_1 '📅 Meeting Index' should be the first block")

        # Check for heading_2 '📊 Meeting Summary Statistics'
        summary_heading_found = False
        summary_index = -1
        for i, block in enumerate(page_blocks):
            if block.get("type") == "heading2" and "meeting summary statistics" in block.get("content", "").lower():
                summary_heading_found = True
                summary_index = i
                break

        if not summary_heading_found:
            errors.append("[X] heading_2 '📊 Meeting Summary Statistics' not found")
        else:
            checks_passed.append("[C] heading_2 '📊 Meeting Summary Statistics' found")

        # Check for blue callout with 📈 icon
        callout_found = False
        for i in range(summary_index + 1, len(page_blocks)):
            block = page_blocks[i]
            if block.get("type") == "callout":
                props = block.get("properties", {})
                content = block.get("content", "")
                if "blue" in props.get("backgroundColor", "") and props.get("icon") == "📈":
                    if "total meetings" in content.lower():
                        callout_found = True
                        break
            elif block.get("type") == "heading2":
                break

        if not callout_found:
            errors.append("[X] Blue callout with 📈 icon and 'Total meetings tracked' not found")
        else:
            checks_passed.append("[C] Blue callout with 📈 icon and 'Total meetings tracked' found")

        # Check for heading_2 '🗓️ Recent Meetings'
        recent_heading_found = False
        recent_index = -1
        for i, block in enumerate(page_blocks):
            if block.get("type") == "heading2" and "recent meetings" in block.get("content", "").lower():
                recent_heading_found = True
                recent_index = i
                break

        if not recent_heading_found:
            errors.append("[X] heading_2 '🗓️ Recent Meetings' not found")
        else:
            checks_passed.append("[C] heading_2 '🗓️ Recent Meetings' found")

        # Check for numbered list
        numbered_items = 0
        for i in range(recent_index + 1, len(page_blocks)):
            block = page_blocks[i]
            if block.get("type") == "numberedList":
                numbered_items += 1
            elif block.get("type") in ["heading2", "heading3", "divider"]:
                break

        if numbered_items < 2:
            errors.append(f"[X] Expected at least 2 numbered list items for meetings, found {numbered_items}")
        else:
            checks_passed.append(f"[C] Found at least 2 numbered list items for meetings ({numbered_items})")

        # Check for heading_3 '🔍 Quick Links'
        quick_links_found = False
        quick_links_index = -1
        for i, block in enumerate(page_blocks):
            if block.get("type") == "heading3" and "quick links" in block.get("content", "").lower():
                quick_links_found = True
                quick_links_index = i
                break

        if not quick_links_found:
            errors.append("[X] heading_3 '🔍 Quick Links' not found")
        else:
            checks_passed.append("[C] heading_3 '🔍 Quick Links' found")

        # Check for bookmark blocks
        bookmark_count = 0
        for i in range(quick_links_index + 1, len(page_blocks)):
            block = page_blocks[i]
            if block.get("type") == "bookmark":
                bookmark_count += 1
            elif block.get("type") in ["heading2", "heading3"]:
                break

        if bookmark_count < 2:
            errors.append(f"[X] Expected at least 2 bookmark blocks, found {bookmark_count}")
        else:
            checks_passed.append(f"[C] Found at least 2 bookmark blocks ({bookmark_count})")

        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_design_system_audit_report(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Design System Audit Report creation."""
    errors: list[str] = []
    checks_passed: list[str] = []

    
    # Find Design System Audit Report page
    try:
        audit_page = _find_page_by_title(final_state_backend, "Design System Audit Report")
        if not audit_page:
            errors.append("[X] Design System Audit Report page not found")
        else:
            checks_passed.append("[C] Design System Audit Report page found")
    
        # Check it's a child of page-35 (Design System)
        if audit_page.get("parentId") != "page-35":
            errors.append(f"[X] Audit Report must be child of page-35, found parentId: {audit_page.get('parentId')}")
        else:
            checks_passed.append(f"[C] Audit Report must be child of page-35, found parentId: {audit_page.get('parentId')}")
    
        page_blocks = sorted(_get_blocks_for_page(final_state_backend, audit_page["_id"]), key=lambda b: b.get("order", 0))
    
        # Check for required headings
        h1_found = any(b.get("type") == "heading1" and "🎯" in b.get("content", "") and "audit report" in b.get("content", "").lower() for b in page_blocks)
        if not h1_found:
            errors.append("[X] heading_1 '🎯 Design System Audit Report' not found")
        else:
            checks_passed.append("[C] heading_1 '🎯 Design System Audit Report' found")
    
        component_inventory = any(b.get("type") == "heading2" and "📁" in b.get("content", "") and "component inventory" in b.get("content", "").lower() for b in page_blocks)
        if not component_inventory:
            errors.append("[X] heading_2 '📁 Component Inventory' not found")
        else:
            checks_passed.append("[C] heading_2 '📁 Component Inventory' found")
    
        favorite_components = any(b.get("type") == "heading2" and "🔍" in b.get("content", "") and "favorite" in b.get("content", "").lower() for b in page_blocks)
        if not favorite_components:
            errors.append("[X] heading_2 '🔍 Favorite Components' not found")
        else:
            checks_passed.append("[C] heading_2 '🔍 Favorite Components' found")
    
        publishing_status = any(b.get("type") == "heading2" and "📊" in b.get("content", "") and "publishing status" in b.get("content", "").lower() for b in page_blocks)
        if not publishing_status:
            errors.append("[X] heading_2 '📊 Publishing Status' not found")
        else:
            checks_passed.append("[C] heading_2 '📊 Publishing Status' found")
    
        # Check for purple (blue as substitute) callout with 💜 icon
        callout_found = False
        for b in page_blocks:
            if b.get("type") == "callout":
                content = b.get("content", "")
                props = b.get("properties", {})
                bg = props.get("backgroundColor", "")
                if ("blue" in bg or "purple" in bg) and props.get("icon") == "💜" and "maintained by" in content.lower():
                    callout_found = True
                    break
    
        if not callout_found:
            errors.append("[X] Purple/blue callout with 💜 icon and 'maintained by' not found")
        else:
            checks_passed.append("[C] Purple/blue callout with 💜 icon and 'maintained by' found")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_engineering_wiki_docker_config(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Engineering Wiki Docker Configuration section."""
    errors: list[str] = []
    checks_passed: list[str] = []

    
    # Find Engineering Wiki page
    try:
        wiki_page = _find_page_by_title(final_state_backend, "Engineering Wiki")
        if not wiki_page:
            errors.append("[X] Engineering Wiki page not found")
        else:
            checks_passed.append("[C] Engineering Wiki page found")
    
        page_blocks = sorted(_get_blocks_for_page(final_state_backend, wiki_page["_id"]), key=lambda b: b.get("order", 0))
    
        # Find Docker Configuration heading
        docker_heading_found = False
        for b in page_blocks:
            if b.get("type") == "heading3" and "🐳" in b.get("content", "") and "docker" in b.get("content", "").lower():
                docker_heading_found = True
                break
    
        if not docker_heading_found:
            errors.append("[X] heading_3 '🐳 Docker Configuration' not found")
        else:
            checks_passed.append("[C] heading_3 '🐳 Docker Configuration' found")
    
        # Check for yaml code block
        yaml_found = False
        for b in page_blocks:
            if b.get("type") == "code":
                props = b.get("properties", {})
                if props.get("language") == "yaml" and "version" in b.get("content", "") and "services" in b.get("content", ""):
                    yaml_found = True
                    break
    
        if not yaml_found:
            errors.append("[X] YAML code block with Docker configuration not found")
        else:
            checks_passed.append("[C] YAML code block with Docker configuration found")
    
        # Check for numbered list with 3 items
        numbered_count = sum(1 for b in page_blocks if b.get("type") == "numberedList")
        if numbered_count < 3:
            errors.append(f"[X] Expected at least 3 numbered list items, found {numbered_count}")
        else:
            checks_passed.append(f"[C] Found at least 3 numbered list items ({numbered_count})")
    
        # Check for Tech Stack with Docker + Kubernetes
        tech_stack_found = False
        for b in page_blocks:
            if b.get("type") == "bulletedList" and "docker" in b.get("content", "").lower() and "kubernetes" in b.get("content", "").lower():
                tech_stack_found = True
                break
    
        if not tech_stack_found:
            errors.append("[X] 'Infrastructure: Docker + Kubernetes' bullet point not found in Tech Stack")
        else:
            checks_passed.append("[C] 'Infrastructure: Docker + Kubernetes' bullet point found in Tech Stack")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_company_handbook_complex_reorg(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Company Handbook complex reorganization."""
    errors: list[str] = []
    checks_passed: list[str] = []

    
    try:
        handbook_page = _find_page_by_title(final_state_backend, "Company Handbook")
        if not handbook_page:
            errors.append("[X] Company Handbook page not found")
        else:
            checks_passed.append("[C] Company Handbook page found")
    
        page_blocks = sorted(_get_blocks_for_page(final_state_backend, handbook_page["_id"]), key=lambda b: b.get("order", 0))
    
        # Check for International Work heading
        intl_work_found = False
        for b in page_blocks:
            if b.get("type") == "heading3" and "🌐" in b.get("content", "") and "international work" in b.get("content", "").lower():
                intl_work_found = True
                break
    
        if not intl_work_found:
            errors.append("[X] heading_3 '🌐 International Work' not found")
        else:
            checks_passed.append("[C] heading_3 '🌐 International Work' found")
    
        # Check for yellow callout with ✈️
        travel_callout_found = False
        for b in page_blocks:
            if b.get("type") == "callout":
                props = b.get("properties", {})
                content = b.get("content", "")
                if "yellow" in props.get("backgroundColor", "") and props.get("icon") == "✈️" and "visa" in content.lower():
                    travel_callout_found = True
                    break
    
        if not travel_callout_found:
            errors.append("[X] Yellow callout with ✈️ and visa/tax note not found")
        else:
            checks_passed.append("[C] Yellow callout with ✈️ and visa/tax note found")
    
        # Check for divider and quote at end
        has_divider = any(b.get("type") == "divider" for b in page_blocks)
        has_quote = any(b.get("type") == "quote" and "benefits" in b.get("content", "").lower() and "talent" in b.get("content", "").lower() for b in page_blocks)
    
        if not has_divider:
            errors.append("[X] Divider block not found")
        else:
            checks_passed.append("[C] Divider block found")
        if not has_quote:
            errors.append("[X] Quote block about benefits and talent not found")
        else:
            checks_passed.append("[C] Quote block about benefits and talent found")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_api_documentation_external_resources(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate API Documentation Index with external resources."""
    errors: list[str] = []
    checks_passed: list[str] = []

    
    # Find API Documentation Index page
    try:
        api_index = _find_page_by_title(final_state_backend, "API Documentation Index")
        if not api_index:
            errors.append("[X] API Documentation Index page not found")
        else:
            checks_passed.append("[C] API Documentation Index page found")
    
        # Check it's under API Documentation
        api_doc_page = _find_page_by_title(final_state_backend, "API Documentation")
        if not api_doc_page or api_index.get("parentId") != api_doc_page.get("_id"):
            errors.append("[X] API Documentation Index must be child of API Documentation page")
        else:
            checks_passed.append("[C] API Documentation Index must be child of API Documentation page")
    
        page_blocks = sorted(_get_blocks_for_page(final_state_backend, api_index["_id"]), key=lambda b: b.get("order", 0))
    
        # Check for required headings
        h1_found = any(b.get("type") == "heading1" and "📚" in b.get("content", "") for b in page_blocks)
        if not h1_found:
            errors.append("[X] heading_1 '📚 API Documentation Index' not found")
        else:
            checks_passed.append("[C] heading_1 '📚 API Documentation Index' found")
    
        quick_nav = any(b.get("type") == "heading2" and "🔍" in b.get("content", "") and "quick navigation" in b.get("content", "").lower() for b in page_blocks)
        if not quick_nav:
            errors.append("[X] heading_2 '🔍 Quick Navigation' not found")
        else:
            checks_passed.append("[C] heading_2 '🔍 Quick Navigation' found")
    
        external_refs = any(b.get("type") == "heading2" and "🌐" in b.get("content", "") and "external" in b.get("content", "").lower() for b in page_blocks)
        if not external_refs:
            errors.append("[X] heading_2 '🌐 External References' not found")
        else:
            checks_passed.append("[C] heading_2 '🌐 External References' found")
    
        dev_tools = any(b.get("type") == "heading2" and "🛠️" in b.get("content", "") and "development tools" in b.get("content", "").lower() for b in page_blocks)
        if not dev_tools:
            errors.append("[X] heading_2 '🛠️ Development Tools' not found")
        else:
            checks_passed.append("[C] heading_2 '🛠️ Development Tools' found")
    
        # Check for gray callout
        gray_callout_found = any(b.get("type") == "callout" and "gray" in b.get("properties", {}).get("backgroundColor", "") for b in page_blocks)
        if not gray_callout_found:
            errors.append("[X] Gray callout not found")
        else:
            checks_passed.append("[C] Gray callout found")
    
        # Check for bookmarks
        bookmark_count = sum(1 for b in page_blocks if b.get("type") == "bookmark")
        if bookmark_count < 2:
            errors.append(f"[X] Expected at least 2 bookmarks, found {bookmark_count}")
        else:
            checks_passed.append(f"[C] Found at least 2 bookmarks ({bookmark_count})")
    
        # Check for italic paragraph at end
        italic_found = False
        for b in page_blocks:
            if b.get("type") == "paragraph":
                content = b.get("content", "")
                if content.startswith("*") and content.endswith("*") and "code examples" in content.lower():
                    italic_found = True
                    break
    
        if not italic_found:
            errors.append("[X] Italic paragraph about Code Examples Repository not found")
        else:
            checks_passed.append("[C] Italic paragraph about Code Examples Repository found")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_team_resource_library_creation(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Team Resource Library creation."""
    errors: list[str] = []
    checks_passed: list[str] = []

    
    # Find Team Resource Library page
    try:
        library_page = _find_page_by_title(final_state_backend, "Team Resource Library")
        if not library_page:
            errors.append("[X] Team Resource Library page not found")
        else:
            checks_passed.append("[C] Team Resource Library page found")
    
        # Check it's at workspace root (no parentId or parentId is workspace)
        parent_id = library_page.get("parentId")
        if parent_id and parent_id.startswith("page-"):
            errors.append(f"[X] Team Resource Library should be at workspace root, found parentId: {parent_id}")
        else:
            checks_passed.append(f"[C] Team Resource Library should be at workspace root, found parentId: {parent_id}")
    
        page_blocks = sorted(_get_blocks_for_page(final_state_backend, library_page["_id"]), key=lambda b: b.get("order", 0))
    
        # Check for required headings
        h1_found = any(b.get("type") == "heading1" and "📚" in b.get("content", "") and "team resource library" in b.get("content", "").lower() for b in page_blocks)
        if not h1_found:
            errors.append("[X] heading_1 '📚 Team Resource Library' not found")
        else:
            checks_passed.append("[C] heading_1 '📚 Team Resource Library' found")
    
        quick_nav = any(b.get("type") == "heading2" and "🔗" in b.get("content", "") and "quick navigation" in b.get("content", "").lower() for b in page_blocks)
        if not quick_nav:
            errors.append("[X] heading_2 '🔗 Quick Navigation' not found")
        else:
            checks_passed.append("[C] heading_2 '🔗 Quick Navigation' found")
    
        onboarding_res = any(b.get("type") == "heading2" and "📋" in b.get("content", "") and "onboarding" in b.get("content", "").lower() for b in page_blocks)
        if not onboarding_res:
            errors.append("[X] heading_2 '📋 Onboarding Resources' not found")
        else:
            checks_passed.append("[C] heading_2 '📋 Onboarding Resources' found")
    
        # Check for yellow callout with 🔄
        sync_callout_found = False
        for b in page_blocks:
            if b.get("type") == "callout":
                props = b.get("properties", {})
                content = b.get("content", "")
                if "yellow" in props.get("backgroundColor", "") and props.get("icon") == "🔄" and "sync" in content.lower():
                    sync_callout_found = True
                    break
    
        if not sync_callout_found:
            errors.append("[X] Yellow callout with 🔄 and 'sync' message not found")
        else:
            checks_passed.append("[C] Yellow callout with 🔄 and 'sync' message found")
    
        # Check for bulleted lists referencing Company Handbook
        handbook_refs = sum(1 for b in page_blocks if b.get("type") == "bulletedList" and "company handbook" in b.get("content", "").lower())
        if handbook_refs < 2:
            errors.append(f"[X] Expected at least 2 bulleted lists referencing Company Handbook, found {handbook_refs}")
        else:
            checks_passed.append(f"[C] Found at least 2 bulleted lists referencing Company Handbook ({handbook_refs})")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_weekly_standup_blockers_section(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Weekly Standup Template blockers section."""
    errors: list[str] = []
    checks_passed: list[str] = []

    
    try:
        standup_page = _find_page_by_title(final_state_backend, "Weekly Standup Template")
        if not standup_page:
            errors.append("[X] Weekly Standup Template page not found")
        else:
            checks_passed.append("[C] Weekly Standup Template page found")
    
        page_blocks = sorted(_get_blocks_for_page(final_state_backend, standup_page["_id"]), key=lambda b: b.get("order", 0))
    
        # Check for Blockers & Dependencies heading
        blockers_heading_found = False
        for b in page_blocks:
            if b.get("type") == "heading2" and "🚧" in b.get("content", "") and "blocker" in b.get("content", "").lower():
                blockers_heading_found = True
                break
    
        if not blockers_heading_found:
            errors.append("[X] heading_2 '🚧 Blockers & Dependencies' not found")
        else:
            checks_passed.append("[C] heading_2 '🚧 Blockers & Dependencies' found")
    
        # Check for red callout with ⚠️
        red_callout_found = False
        for b in page_blocks:
            if b.get("type") == "callout":
                props = b.get("properties", {})
                content = b.get("content", "")
                if "red" in props.get("backgroundColor", "") and props.get("icon") == "⚠️":
                    red_callout_found = True
                    break
    
        if not red_callout_found:
            errors.append("[X] Red callout with ⚠️ not found")
        else:
            checks_passed.append("[C] Red callout with ⚠️ found")
    
        # Check for bookmark to slack
        bookmark_found = any(b.get("type") == "bookmark" and "slack" in b.get("properties", {}).get("url", "").lower() for b in page_blocks)
        if not bookmark_found:
            errors.append("[X] Bookmark to Slack blockers channel not found")
        else:
            checks_passed.append("[C] Bookmark to Slack blockers channel found")
    
        # Check for Disney quote
        disney_quote_found = any(b.get("type") == "quote" and "disney" in b.get("content", "").lower() for b in page_blocks)
        if not disney_quote_found:
            errors.append("[X] Walt Disney quote not found")
        else:
            checks_passed.append("[C] Walt Disney quote found")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_api_documentation_authentication(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate API Documentation with authentication section."""
    errors: list[str] = []
    checks_passed: list[str] = []

    
    try:
        api_doc_page = _find_page_by_title(final_state_backend, "API Documentation")
        if not api_doc_page:
            errors.append("[X] API Documentation page not found")
        else:
            checks_passed.append("[C] API Documentation page found")
    
        # Check for 📖 icon
        if api_doc_page.get("icon") != "📖":
            errors.append(f"[X] API Documentation icon should be 📖, found: {api_doc_page.get('icon')}")
        else:
            checks_passed.append(f"[C] API Documentation icon should be 📖, found: {api_doc_page.get('icon')}")
    
        page_blocks = sorted(_get_blocks_for_page(final_state_backend, api_doc_page["_id"]), key=lambda b: b.get("order", 0))
    
        # Check for Authentication heading
        auth_heading = any(b.get("type") == "heading2" and "🔌" in b.get("content", "") and "authentication" in b.get("content", "").lower() for b in page_blocks)
        if not auth_heading:
            errors.append("[X] heading_2 '🔌 Authentication' not found")
        else:
            checks_passed.append("[C] heading_2 '🔌 Authentication' found")
    
        # Check for javascript code block
        js_code_found = False
        for b in page_blocks:
            if b.get("type") == "code":
                props = b.get("properties", {})
                if props.get("language") == "javascript" and "Authorization" in b.get("content", ""):
                    js_code_found = True
                    break
    
        if not js_code_found:
            errors.append("[X] JavaScript code block with Authorization header not found")
        else:
            checks_passed.append("[C] JavaScript code block with Authorization header found")
    
        # Check for yellow security callout
        security_callout = False
        for b in page_blocks:
            if b.get("type") == "callout":
                props = b.get("properties", {})
                content = b.get("content", "")
                if "yellow" in props.get("backgroundColor", "") and props.get("icon") == "⚠️" and "api key" in content.lower():
                    security_callout = True
                    break
    
        if not security_callout:
            errors.append("[X] Yellow security callout with ⚠️ not found")
        else:
            checks_passed.append("[C] Yellow security callout with ⚠️ found")
    
        # Check for Endpoints heading
        endpoints_heading = any(b.get("type") == "heading2" and "📡" in b.get("content", "") and "endpoint" in b.get("content", "").lower() for b in page_blocks)
        if not endpoints_heading:
            errors.append("[X] heading_2 '📡 Endpoints' not found")
        else:
            checks_passed.append("[C] heading_2 '📡 Endpoints' found")
    
        # Check for bash code block with curl
        bash_code_found = False
        for b in page_blocks:
            if b.get("type") == "code":
                props = b.get("properties", {})
                if props.get("language") == "bash" and "curl" in b.get("content", ""):
                    bash_code_found = True
                    break
    
        if not bash_code_found:
            errors.append("[X] Bash code block with curl command not found")
        else:
            checks_passed.append("[C] Bash code block with curl command found")
    
        # Check for bookmark
        bookmark_found = any(b.get("type") == "bookmark" for b in page_blocks)
        if not bookmark_found:
            errors.append("[X] Bookmark to API docs not found")
        else:
            checks_passed.append("[C] Bookmark to API docs found")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_bug_tracker_severity_classification(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Bug Tracker severity classification section."""
    errors: list[str] = []
    checks_passed: list[str] = []

    
    try:
        bug_tracker = _find_page_by_title(final_state_backend, "Bug Tracker")
        if not bug_tracker:
            errors.append("[X] Bug Tracker page not found")
        else:
            checks_passed.append("[C] Bug Tracker page found")
    
        page_blocks = sorted(_get_blocks_for_page(final_state_backend, bug_tracker["_id"]), key=lambda b: b.get("order", 0))
    
        # Check for Bug Severity Levels heading
        severity_heading_found = False
        for b in page_blocks:
            if b.get("type") == "heading2" and "🔥" in b.get("content", "") and "severity" in b.get("content", "").lower():
                severity_heading_found = True
                break
    
        if not severity_heading_found:
            errors.append("[X] heading_2 '🔥 Bug Severity Levels' not found")
        else:
            checks_passed.append("[C] heading_2 '🔥 Bug Severity Levels' found")
    
        # Check for High Priority heading
        high_priority = any(b.get("type") == "heading3" and "🚨" in b.get("content", "") and "high priority" in b.get("content", "").lower() for b in page_blocks)
        if not high_priority:
            errors.append("[X] heading_3 '🚨 High Priority' not found")
        else:
            checks_passed.append("[C] heading_3 '🚨 High Priority' found")
    
        # Check for Standard Priority heading
        standard_priority = any(b.get("type") == "heading3" and "⚡" in b.get("content", "") and "standard priority" in b.get("content", "").lower() for b in page_blocks)
        if not standard_priority:
            errors.append("[X] heading_3 '⚡ Standard Priority' not found")
        else:
            checks_passed.append("[C] heading_3 '⚡ Standard Priority' found")
    
        # Check for red callout with ⚠️ and count
        critical_callout_found = False
        for b in page_blocks:
            if b.get("type") == "callout":
                props = b.get("properties", {})
                content = b.get("content", "")
                if "red" in props.get("backgroundColor", "") and props.get("icon") == "⚠️" and "critical" in content.lower():
                    critical_callout_found = True
                    break
    
        if not critical_callout_found:
            errors.append("[X] Red callout with ⚠️ and critical issues count not found")
        else:
            checks_passed.append("[C] Red callout with ⚠️ and critical issues count found")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_company_handbook_culture_section_2(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Company Handbook culture section addition."""
    errors: list[str] = []
    checks_passed: list[str] = []

    
    try:
        handbook_page = _find_page_by_title(final_state_backend, "Company Handbook")
        if not handbook_page:
            errors.append("[X] Company Handbook page not found")
        else:
            checks_passed.append("[C] Company Handbook page found")
    
        page_blocks = sorted(_get_blocks_for_page(final_state_backend, handbook_page["_id"]), key=lambda b: b.get("order", 0))
    
        # Check for Company Culture heading
        culture_heading_found = False
        for b in page_blocks:
            if b.get("type") == "heading2" and "🏢" in b.get("content", "") and "company culture" in b.get("content", "").lower():
                culture_heading_found = True
                break
    
        if not culture_heading_found:
            errors.append("[X] heading_2 '🏢 Company Culture' not found")
        else:
            checks_passed.append("[C] heading_2 '🏢 Company Culture' found")
    
        # Check for 3 bulleted lists about values
        value_bullets = []
        for b in page_blocks:
            if b.get("type") == "bulletedList":
                content = b.get("content", "").lower()
                if any(word in content for word in ["innovation", "collaboration", "excellence"]):
                    value_bullets.append(b)
    
        if len(value_bullets) < 3:
            errors.append(f"[X] Expected 3 value bullet points, found {len(value_bullets)}")
        else:
            checks_passed.append(f"[C] Found 3 value bullet points as expected")
    
        # Check for red callout about policies
        policy_callout_found = False
        for b in page_blocks:
            if b.get("type") == "callout":
                props = b.get("properties", {})
                content = b.get("content", "")
                if "red" in props.get("backgroundColor", "") and props.get("icon") == "⚠️" and "policies" in content.lower():
                    policy_callout_found = True
                    break
    
        if not policy_callout_found:
            errors.append("[X] Red callout with ⚠️ about policies not found")
        else:
            checks_passed.append("[C] Red callout with ⚠️ about policies found")
    
        # Check for quote with section count
        quote_with_count = False
        for b in page_blocks:
            if b.get("type") == "quote" and "sections" in b.get("content", "").lower() and "handbook" in b.get("content", "").lower():
                quote_with_count = True
                break
    
        if not quote_with_count:
            errors.append("[X] Quote with section count not found")
        else:
            checks_passed.append("[C] Quote with section count found")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_code_examples_advanced_patterns(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Code Examples Advanced Patterns section."""
    errors: list[str] = []
    checks_passed: list[str] = []

    
    try:
        code_examples = _find_page_by_title(final_state_backend, "Code Examples Repository")
        if not code_examples:
            errors.append("[X] Code Examples Repository page not found")
        else:
            checks_passed.append("[C] Code Examples Repository page found")
    
        page_blocks = sorted(_get_blocks_for_page(final_state_backend, code_examples["_id"]), key=lambda b: b.get("order", 0))
    
        # Check for Advanced Patterns heading
        advanced_heading_found = False
        for b in page_blocks:
            if b.get("type") == "heading2" and "🚀" in b.get("content", "") and "advanced patterns" in b.get("content", "").lower():
                advanced_heading_found = True
                break
    
        if not advanced_heading_found:
            errors.append("[X] heading_2 '🚀 Advanced Patterns' not found")
        else:
            checks_passed.append("[C] heading_2 '🚀 Advanced Patterns' found")
    
        # Check for yellow callout with 💡
        callout_found = False
        for b in page_blocks:
            if b.get("type") == "callout":
                props = b.get("properties", {})
                content = b.get("content", "")
                if "yellow" in props.get("backgroundColor", "") and props.get("icon") == "💡" and "senior developers" in content.lower():
                    callout_found = True
                    break
    
        if not callout_found:
            errors.append("[X] Yellow callout with 💡 about senior developers not found")
        else:
            checks_passed.append("[C] Yellow callout with 💡 about senior developers found")
    
        # Check for typescript code block with async pattern
        ts_code_found = False
        for b in page_blocks:
            if b.get("type") == "code":
                props = b.get("properties", {})
                if props.get("language") == "typescript" and "safeAsync" in b.get("content", ""):
                    ts_code_found = True
                    break
    
        if not ts_code_found:
            errors.append("[X] TypeScript code block with safeAsync pattern not found")
        else:
            checks_passed.append("[C] TypeScript code block with safeAsync pattern found")
    
        # Check for image block
        image_found = any(b.get("type") == "image" and "async-pattern" in b.get("properties", {}).get("url", "") for b in page_blocks)
        if not image_found:
            errors.append("[X] Image block for async pattern diagram not found")
        else:
            checks_passed.append("[C] Image block for async pattern diagram found")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_product_requirements_section_swap(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Product Requirements section swap."""
    errors: list[str] = []
    checks_passed: list[str] = []

    
    try:
        prd_page = _find_page_by_title(final_state_backend, "Comprehensive Product Requirements Document")
        if not prd_page:
            errors.append("[X] Comprehensive Product Requirements Document page not found")
        else:
            checks_passed.append("[C] Comprehensive Product Requirements Document page found")
    
        page_blocks = sorted(_get_blocks_for_page(final_state_backend, prd_page["_id"]), key=lambda b: b.get("order", 0))
    
        # Check for Section Statistics heading
        stats_heading_found = False
        for b in page_blocks:
            if b.get("type") == "heading2" and "section statistics" in b.get("content", "").lower():
                stats_heading_found = True
                break
    
        if not stats_heading_found:
            errors.append("[X] heading_2 'Section Statistics' not found")
        else:
            checks_passed.append("[C] heading_2 'Section Statistics' found")
    
        # Check for paragraphs with counts
        count_paragraphs = sum(1 for b in page_blocks if b.get("type") == "paragraph" and ("overview section" in b.get("content", "").lower() or "user stories section" in b.get("content", "").lower()))
        if count_paragraphs < 2:
            errors.append(f"[X] Expected 2 paragraphs with section counts, found {count_paragraphs}")
        else:
            checks_passed.append(f"[C] Found 2 paragraphs with section counts as expected")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_sprint_planning_velocity_calc(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Sprint Planning velocity calculation section."""
    errors: list[str] = []
    checks_passed: list[str] = []

    
    try:
        sprint_page = _find_page_by_title(final_state_backend, "Sprint Planning - Jan 15")
        if not sprint_page:
            errors.append("[X] Sprint Planning - Jan 15 page not found")
        else:
            checks_passed.append("[C] Sprint Planning - Jan 15 page found")
    
        page_blocks = sorted(_get_blocks_for_page(final_state_backend, sprint_page["_id"]), key=lambda b: b.get("order", 0))
    
        # Check for Sprint Velocity Calculation heading
        velocity_heading_found = False
        for b in page_blocks:
            if b.get("type") == "heading3" and "📊" in b.get("content", "") and "velocity" in b.get("content", "").lower():
                velocity_heading_found = True
                break
    
        if not velocity_heading_found:
            errors.append("[X] heading_3 '📊 Sprint Velocity Calculation' not found")
        else:
            checks_passed.append("[C] heading_3 '📊 Sprint Velocity Calculation' found")
    
        # Check for bold paragraph
        bold_para_found = False
        for b in page_blocks:
            if b.get("type") == "paragraph" and "**" in b.get("content", ""):
                bold_para_found = True
                break
    
        if not bold_para_found:
            errors.append("[X] Bold paragraph '**Sprint Points Analysis**' not found")
        else:
            checks_passed.append("[C] Bold paragraph '**Sprint Points Analysis**' found")
    
        # Check for yellow callout with 🎯
        callout_found = False
        for b in page_blocks:
            if b.get("type") == "callout":
                props = b.get("properties", {})
                content = b.get("content", "")
                if "yellow" in props.get("backgroundColor", "") and props.get("icon") == "🎯" and "total sprint points" in content.lower():
                    callout_found = True
                    break
    
        if not callout_found:
            errors.append("[X] Yellow callout with 🎯 and sprint points calculation not found")
        else:
            checks_passed.append("[C] Yellow callout with 🎯 and sprint points calculation found")
    
        # Check for divider
        has_divider = any(b.get("type") == "divider" for b in page_blocks)
        if not has_divider:
            errors.append("[X] Divider block not found")
        else:
            checks_passed.append("[C] Divider block found")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_code_examples_python_performance(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Code Examples Python performance optimization section."""
    errors: list[str] = []
    checks_passed: list[str] = []

    
    try:
        code_examples = _find_page_by_title(final_state_backend, "Code Examples Repository")
        if not code_examples:
            errors.append("[X] Code Examples Repository page not found")
        else:
            checks_passed.append("[C] Code Examples Repository page found")
    
        page_blocks = sorted(_get_blocks_for_page(final_state_backend, code_examples["_id"]), key=lambda b: b.get("order", 0))
    
        # Check for Performance Optimization heading
        perf_heading_found = False
        for b in page_blocks:
            if b.get("type") == "heading3" and "🔧" in b.get("content", "") and "performance" in b.get("content", "").lower():
                perf_heading_found = True
                break
    
        if not perf_heading_found:
            errors.append("[X] heading_3 '🔧 Performance Optimization' not found")
        else:
            checks_passed.append("[C] heading_3 '🔧 Performance Optimization' found")
    
        # Check for python code block with lru_cache
        python_code_found = False
        for b in page_blocks:
            if b.get("type") == "code":
                props = b.get("properties", {})
                content = b.get("content", "")
                if props.get("language") == "python" and "lru_cache" in content and "fibonacci" in content.lower():
                    python_code_found = True
                    break
    
        if not python_code_found:
            errors.append("[X] Python code block with lru_cache and fibonacci not found")
        else:
            checks_passed.append("[C] Python code block with lru_cache and fibonacci found")
    
        # Check for paragraph about memoization
        memo_para_found = False
        for b in page_blocks:
            if b.get("type") == "paragraph" and "memoization" in b.get("content", "").lower() and "o(n)" in b.get("content", "").lower():
                memo_para_found = True
                break
    
        if not memo_para_found:
            errors.append("[X] Paragraph about memoization complexity not found")
        else:
            checks_passed.append("[C] Paragraph about memoization complexity found")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_weekly_standup_milestones(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Weekly Standup milestones section."""
    errors: list[str] = []
    checks_passed: list[str] = []

    
    try:
        standup_page = _find_page_by_title(final_state_backend, "Weekly Standup Template")
        if not standup_page:
            errors.append("[X] Weekly Standup Template page not found")
        else:
            checks_passed.append("[C] Weekly Standup Template page found")
    
        page_blocks = sorted(_get_blocks_for_page(final_state_backend, standup_page["_id"]), key=lambda b: b.get("order", 0))
    
        # Check for Weekly Milestones heading
        milestones_heading_found = False
        for b in page_blocks:
            if b.get("type") == "heading2" and "📅" in b.get("content", "") and "weekly milestones" in b.get("content", "").lower():
                milestones_heading_found = True
                break
    
        if not milestones_heading_found:
            errors.append("[X] heading_2 '📅 Weekly Milestones' not found")
        else:
            checks_passed.append("[C] heading_2 '📅 Weekly Milestones' found")
    
        # Check for yellow callout with 🎯
        callout_found = False
        for b in page_blocks:
            if b.get("type") == "callout":
                props = b.get("properties", {})
                content = b.get("content", "")
                if "yellow" in props.get("backgroundColor", "") and props.get("icon") == "🎯" and "focus areas" in content.lower():
                    callout_found = True
                    break
    
        if not callout_found:
            errors.append("[X] Yellow callout with 🎯 and Focus Areas not found")
        else:
            checks_passed.append("[C] Yellow callout with 🎯 and Focus Areas found")
    
        # Check for specific milestone todos
        performance_todo = any(b.get("type") == "todo" and "⚡" in b.get("content", "") and "optimize" in b.get("content", "").lower() for b in page_blocks)
        security_todo = any(b.get("type") == "todo" and "🔒" in b.get("content", "") and "authentication" in b.get("content", "").lower() for b in page_blocks)
        ux_todo = any(b.get("type") == "todo" and "🎨" in b.get("content", "") and "onboarding" in b.get("content", "").lower() for b in page_blocks)
    
        if not (performance_todo and security_todo and ux_todo):
            errors.append("[X] Expected 3 specific milestone todos with emojis not found")
        else:
            checks_passed.append("[C] Expected 3 specific milestone todos with emojis found")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_team_directory_remote_members(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Team Directory remote members section."""
    errors: list[str] = []
    checks_passed: list[str] = []

    
    try:
        team_dir = _find_page_by_title(final_state_backend, "Team Directory")
        if not team_dir:
            errors.append("[X] Team Directory page not found")
        else:
            checks_passed.append("[C] Team Directory page found")
    
        page_blocks = sorted(_get_blocks_for_page(final_state_backend, team_dir["_id"]), key=lambda b: b.get("order", 0))
    
        # Check for Remote Team Members heading
        remote_heading_found = False
        for b in page_blocks:
            if b.get("type") == "heading2" and "🌍" in b.get("content", "") and "remote" in b.get("content", "").lower():
                remote_heading_found = True
                break
    
        if not remote_heading_found:
            errors.append("[X] heading_2 '🌍 Remote Team Members' not found")
        else:
            checks_passed.append("[C] heading_2 '🌍 Remote Team Members' found")
    
        # Check for italic paragraph
        italic_para_found = False
        for b in page_blocks:
            if b.get("type") == "paragraph" and b.get("content", "").startswith("*") and "distributed" in b.get("content", "").lower():
                italic_para_found = True
                break
    
        if not italic_para_found:
            errors.append("[X] Italic paragraph about distributed team not found")
        else:
            checks_passed.append("[C] Italic paragraph about distributed team found")
    
        # Check for 3 team members with flag emojis
        flag_bullets = []
        for b in page_blocks:
            if b.get("type") == "bulletedList":
                content = b.get("content", "")
                if any(flag in content for flag in ["🇯🇵", "🇩🇪", "🇧🇷"]):
                    flag_bullets.append(b)
    
        if len(flag_bullets) < 3:
            errors.append(f"[X] Expected 3 bulleted items with country flags, found {len(flag_bullets)}")
        else:
            checks_passed.append(f"[C] Found 3 bulleted items with country flags as expected")
    
        # Check for divider and quote
        has_divider = any(b.get("type") == "divider" for b in page_blocks)
        has_quote = any(b.get("type") == "quote" and "remote work" in b.get("content", "").lower() for b in page_blocks)
    
        if not has_divider:
            errors.append("[X] Divider block not found")
        else:
            checks_passed.append("[C] Divider block found")
        if not has_quote:
            errors.append("[X] Quote about remote work not found")
        else:
            checks_passed.append("[C] Quote about remote work found")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_company_handbook_section_swap_date(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Company Handbook section swap with date callout."""
    errors: list[str] = []
    checks_passed: list[str] = []

    
    try:
        handbook_page = _find_page_by_title(final_state_backend, "Company Handbook")
        if not handbook_page:
            errors.append("[X] Company Handbook page not found")
        else:
            checks_passed.append("[C] Company Handbook page found")
    
        page_blocks = sorted(_get_blocks_for_page(final_state_backend, handbook_page["_id"]), key=lambda b: b.get("order", 0))
    
        # Check for blue callout with 📌
        date_callout_found = False
        for b in page_blocks:
            if b.get("type") == "callout":
                props = b.get("properties", {})
                content = b.get("content", "")
                if "blue" in props.get("backgroundColor", "") and props.get("icon") == "📌" and "reorganized" in content.lower():
                    date_callout_found = True
                    break
    
        if not date_callout_found:
            errors.append("[X] Blue callout with 📌 and reorganization date not found")
        else:
            checks_passed.append("[C] Blue callout with 📌 and reorganization date found")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_company_handbook_benefits_perks(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Company Handbook benefits perks addition."""
    errors: list[str] = []
    checks_passed: list[str] = []

    
    try:
        handbook_page = _find_page_by_title(final_state_backend, "Company Handbook")
        if not handbook_page:
            errors.append("[X] Company Handbook page not found")
        else:
            checks_passed.append("[C] Company Handbook page found")
    
        page_blocks = sorted(_get_blocks_for_page(final_state_backend, handbook_page["_id"]), key=lambda b: b.get("order", 0))
    
        # Check for Additional Perks heading
        perks_heading_found = False
        for b in page_blocks:
            if b.get("type") == "heading3" and "🎁" in b.get("content", "") and "additional perks" in b.get("content", "").lower():
                perks_heading_found = True
                break
    
        if not perks_heading_found:
            errors.append("[X] heading_3 '🎁 Additional Perks' not found")
        else:
            checks_passed.append("[C] heading_3 '🎁 Additional Perks' found")
    
        # Check for 4 specific perk bullets
        home_office = any(b.get("type") == "bulletedList" and "🏠" in b.get("content", "") and "home office" in b.get("content", "").lower() for b in page_blocks)
        gym = any(b.get("type") == "bulletedList" and "🏋️" in b.get("content", "") and "gym" in b.get("content", "").lower() for b in page_blocks)
        snacks = any(b.get("type") == "bulletedList" and "🍎" in b.get("content", "") and "snacks" in b.get("content", "").lower() for b in page_blocks)
        team_building = any(b.get("type") == "bulletedList" and "🎮" in b.get("content", "") and "team building" in b.get("content", "").lower() for b in page_blocks)
    
        if not (home_office and gym and snacks and team_building):
            errors.append("[X] Expected 4 specific perk bullets with emojis not found")
        else:
            checks_passed.append("[C] Expected 4 specific perk bullets with emojis found")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_weekly_standup_sprint_priorities(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Weekly Standup sprint priorities and progress tracker."""
    errors: list[str] = []
    checks_passed: list[str] = []

    
    try:
        standup_page = _find_page_by_title(final_state_backend, "Weekly Standup Template")
        if not standup_page:
            errors.append("[X] Weekly Standup Template page not found")
        else:
            checks_passed.append("[C] Weekly Standup Template page found")
    
        page_blocks = sorted(_get_blocks_for_page(final_state_backend, standup_page["_id"]), key=lambda b: b.get("order", 0))
    
        # Check for Sprint Priorities heading
        priorities_heading_found = False
        for b in page_blocks:
            if b.get("type") == "heading2" and "🎯" in b.get("content", "") and "sprint priorities" in b.get("content", "").lower():
                priorities_heading_found = True
                break
    
        if not priorities_heading_found:
            errors.append("[X] heading_2 '🎯 Sprint Priorities' not found")
        else:
            checks_passed.append("[C] heading_2 '🎯 Sprint Priorities' found")
    
        # Check for 3 priority todos
        refactor_todo = any(b.get("type") == "todo" and "🔧" in b.get("content", "") and "refactor" in b.get("content", "").lower() for b in page_blocks)
        analytics_todo = any(b.get("type") == "todo" and "📊" in b.get("content", "") and "analytics" in b.get("content", "").lower() for b in page_blocks)
        deploy_todo = any(b.get("type") == "todo" and "🚀" in b.get("content", "") and "deploy" in b.get("content", "").lower() for b in page_blocks)
    
        if not (refactor_todo and analytics_todo and deploy_todo):
            errors.append("[X] Expected 3 specific priority todos not found")
        else:
            checks_passed.append("[C] Expected 3 specific priority todos found")
    
        # Check for blue progress callout with 📈
        progress_callout_found = False
        for b in page_blocks:
            if b.get("type") == "callout":
                props = b.get("properties", {})
                content = b.get("content", "")
                if "blue" in props.get("backgroundColor", "") and props.get("icon") == "📈" and "progress update" in content.lower():
                    progress_callout_found = True
                    break
    
        if not progress_callout_found:
            errors.append("[X] Blue callout with 📈 and progress update not found")
        else:
            checks_passed.append("[C] Blue callout with 📈 and progress update found")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_meeting_notes_dashboard(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Meeting Notes dashboard creation."""
    errors: list[str] = []
    checks_passed: list[str] = []

    
    try:
        meeting_notes = _find_page_by_title(final_state_backend, "Meeting Notes")
        if not meeting_notes:
            errors.append("[X] Meeting Notes page not found")
        else:
            checks_passed.append("[C] Meeting Notes page found")
    
        page_blocks = sorted(_get_blocks_for_page(final_state_backend, meeting_notes["_id"]), key=lambda b: b.get("order", 0))
    
        # Check for 2024 Meeting Metrics heading
        metrics_heading_found = False
        for b in page_blocks:
            if b.get("type") == "heading2" and "📊" in b.get("content", "") and "2024" in b.get("content", "") and "meeting metrics" in b.get("content", "").lower():
                metrics_heading_found = True
                break
    
        if not metrics_heading_found:
            errors.append("[X] heading_2 '📊 2024 Meeting Metrics' not found")
        else:
            checks_passed.append("[C] heading_2 '📊 2024 Meeting Metrics' found")
    
        # Check for Insights heading
        insights_heading_found = False
        for b in page_blocks:
            if b.get("type") == "heading2" and "📈" in b.get("content", "") and "insights" in b.get("content", "").lower():
                insights_heading_found = True
                break
    
        if not insights_heading_found:
            errors.append("[X] heading_2 '📈 Insights' not found")
        else:
            checks_passed.append("[C] heading_2 '📈 Insights' found")
    
        # Check for gray and blue callouts
        has_gray_callout = any(b.get("type") == "callout" and "gray" in b.get("properties", {}).get("backgroundColor", "") for b in page_blocks)
        has_blue_callout = any(b.get("type") == "callout" and "blue" in b.get("properties", {}).get("backgroundColor", "") for b in page_blocks)
    
        if not has_gray_callout:
            errors.append("[X] Gray callout for structure info not found")
        else:
            checks_passed.append("[C] Gray callout for structure info found")
        if not has_blue_callout:
            errors.append("[X] Blue callout for participants info not found")
        else:
            checks_passed.append("[C] Blue callout for participants info found")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_team_performance_analytics(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Team Performance Analytics page creation."""
    errors: list[str] = []
    checks_passed: list[str] = []

    
    # Find Team Performance Analytics page
    try:
        analytics_page = _find_page_by_title(final_state_backend, "Team Performance Analytics")
        if not analytics_page:
            errors.append("[X] Team Performance Analytics page not found")
        else:
            checks_passed.append("[C] Team Performance Analytics page found")
    
        # Check it's a child of Team Directory
        team_dir = _find_page_by_title(final_state_backend, "Team Directory")
        if not team_dir or analytics_page.get("parentId") != team_dir.get("_id"):
            errors.append("[X] Team Performance Analytics must be child of Team Directory")
        else:
            checks_passed.append("[C] Team Performance Analytics must be child of Team Directory")
    
        page_blocks = sorted(_get_blocks_for_page(final_state_backend, analytics_page["_id"]), key=lambda b: b.get("order", 0))
    
        # Check for required headings
        h1_found = any(b.get("type") == "heading1" and "📊" in b.get("content", "") and "team performance analytics" in b.get("content", "").lower() for b in page_blocks)
        if not h1_found:
            errors.append("[X] heading_1 '📊 Team Performance Analytics' not found")
        else:
            checks_passed.append("[C] heading_1 '📊 Team Performance Analytics' found")
    
        team_comp = any(b.get("type") == "heading2" and "👥" in b.get("content", "") and "team composition" in b.get("content", "").lower() for b in page_blocks)
        if not team_comp:
            errors.append("[X] heading_2 '👥 Team Composition' not found")
        else:
            checks_passed.append("[C] heading_2 '👥 Team Composition' found")
    
        meeting_part = any(b.get("type") == "heading2" and "📅" in b.get("content", "") and "meeting participation" in b.get("content", "").lower() for b in page_blocks)
        if not meeting_part:
            errors.append("[X] heading_2 '📅 Meeting Participation' not found")
        else:
            checks_passed.append("[C] heading_2 '📅 Meeting Participation' found")
    
        action_items = any(b.get("type") == "heading2" and "🎯" in b.get("content", "") and "action items" in b.get("content", "").lower() for b in page_blocks)
        if not action_items:
            errors.append("[X] heading_2 '🎯 Action Items by Team' not found")
        else:
            checks_passed.append("[C] heading_2 '🎯 Action Items by Team' found")
    
        # Check for yellow callout
        has_yellow_callout = any(b.get("type") == "callout" and "yellow" in b.get("properties", {}).get("backgroundColor", "") for b in page_blocks)
        if not has_yellow_callout:
            errors.append("[X] Yellow callout for meeting summary not found")
        else:
            checks_passed.append("[C] Yellow callout for meeting summary found")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_design_system_component_examples(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Design System component examples section."""
    errors: list[str] = []
    checks_passed: list[str] = []

    
    try:
        design_system = _find_page_by_title(final_state_backend, "Design System")
        if not design_system:
            errors.append("[X] Design System page not found")
        else:
            checks_passed.append("[C] Design System page found")
    
        page_blocks = sorted(_get_blocks_for_page(final_state_backend, design_system["_id"]), key=lambda b: b.get("order", 0))
    
        # Check for Component Examples heading
        examples_heading_found = False
        for b in page_blocks:
            if b.get("type") == "heading2" and "🎨" in b.get("content", "") and "component examples" in b.get("content", "").lower():
                examples_heading_found = True
                break
    
        if not examples_heading_found:
            errors.append("[X] heading_2 '🎨 Component Examples' not found")
        else:
            checks_passed.append("[C] heading_2 '🎨 Component Examples' found")
    
        # Check for jsx code block
        jsx_code_found = False
        for b in page_blocks:
            if b.get("type") == "code":
                props = b.get("properties", {})
                content = b.get("content", "")
                if props.get("language") == "jsx" and "Button" in content and "Card" in content:
                    jsx_code_found = True
                    break
    
        if not jsx_code_found:
            errors.append("[X] JSX code block with Button and Card components not found")
        else:
            checks_passed.append("[C] JSX code block with Button and Card components found")
    
        # Check for blue callout with 🧩
        callout_found = False
        for b in page_blocks:
            if b.get("type") == "callout":
                props = b.get("properties", {})
                content = b.get("content", "")
                if "blue" in props.get("backgroundColor", "") and props.get("icon") == "🧩" and "storybook" in content.lower():
                    callout_found = True
                    break
    
        if not callout_found:
            errors.append("[X] Blue callout with 🧩 and Storybook reference not found")
        else:
            checks_passed.append("[C] Blue callout with 🧩 and Storybook reference found")
    
        # Check for numbered list with 3 items
        numbered_count = sum(1 for b in page_blocks if b.get("type") == "numberedList")
        if numbered_count < 3:
            errors.append(f"[X] Expected at least 3 numbered list items, found {numbered_count}")
        else:
            checks_passed.append(f"[C] Found at least 3 numbered list items ({numbered_count})")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_api_documentation_breaking_changes(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate API Documentation breaking changes section."""
    errors: list[str] = []
    checks_passed: list[str] = []

    
    try:
        api_doc = _find_page_by_title(final_state_backend, "API Documentation")
        if not api_doc:
            errors.append("[X] API Documentation page not found")
        else:
            checks_passed.append("[C] API Documentation page found")
    
        page_blocks = sorted(_get_blocks_for_page(final_state_backend, api_doc["_id"]), key=lambda b: b.get("order", 0))
    
        # Check for red callout with 🚨
        breaking_callout_found = False
        for b in page_blocks:
            if b.get("type") == "callout":
                props = b.get("properties", {})
                content = b.get("content", "")
                if "red" in props.get("backgroundColor", "") and props.get("icon") == "🚨" and "breaking change" in content.lower():
                    breaking_callout_found = True
                    break
    
        if not breaking_callout_found:
            errors.append("[X] Red callout with 🚨 and 'Breaking Change' not found")
        else:
            checks_passed.append("[C] Red callout with 🚨 and 'Breaking Change' found")
    
        # Check for javascript code block with pagination
        js_code_found = False
        for b in page_blocks:
            if b.get("type") == "code":
                props = b.get("properties", {})
                content = b.get("content", "")
                if props.get("language") == "javascript" and "pagination" in content.lower():
                    js_code_found = True
                    break
    
        if not js_code_found:
            errors.append("[X] JavaScript code block with pagination example not found")
        else:
            checks_passed.append("[C] JavaScript code block with pagination example found")
    
        # Check for migration deadline paragraph
        deadline_found = False
        for b in page_blocks:
            if b.get("type") == "paragraph" and "migration deadline" in b.get("content", "").lower():
                deadline_found = True
                break
    
        if not deadline_found:
            errors.append("[X] Migration deadline paragraph not found")
        else:
            checks_passed.append("[C] Migration deadline paragraph found")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

def _validate_project_documentation_reorg(
    final_state_backend: Backend, final_state_frontend: Dict[str, Any]
) -> TaskScore:
    """Validate Project Documentation reorganization."""
    errors: list[str] = []
    checks_passed: list[str] = []

    
    # Find Legacy Architecture page
    try:
        legacy_arch = _find_page_by_title(final_state_backend, "Legacy Architecture")
        if not legacy_arch:
            errors.append("[X] Legacy Architecture page not found")
        else:
            checks_passed.append("[C] Legacy Architecture page found")
    
        # Check it's under Project Documentation
        proj_doc = _find_page_by_title(final_state_backend, "Project Documentation")
        if not proj_doc or legacy_arch.get("parentId") != proj_doc.get("_id"):
            errors.append("[X] Legacy Architecture must be child of Project Documentation")
        else:
            checks_passed.append("[C] Legacy Architecture must be child of Project Documentation")
    
        # Check Backend Architecture is now under Legacy Architecture
        backend_arch = _find_page_by_title(final_state_backend, "Backend Architecture")
        if backend_arch and backend_arch.get("parentId") != legacy_arch.get("_id"):
            errors.append("[X] Backend Architecture must be moved under Legacy Architecture")
        else:
            checks_passed.append("[C] Backend Architecture must be moved under Legacy Architecture")
    
        # Check Project Documentation page for Recent Updates heading
        proj_blocks = sorted(_get_blocks_for_page(final_state_backend, proj_doc["_id"]), key=lambda b: b.get("order", 0))
    
        recent_updates = any(b.get("type") == "heading2" and "🔄" in b.get("content", "") and "recent updates" in b.get("content", "").lower() for b in proj_blocks)
        if not recent_updates:
            errors.append("[X] heading_2 '🔄 Recent Updates' not found on Project Documentation page")
        else:
            checks_passed.append("[C] heading_2 '🔄 Recent Updates' found on Project Documentation page")
    
        # Check for green callout with ✅
        green_callout_found = False
        for b in proj_blocks:
            if b.get("type") == "callout":
                props = b.get("properties", {})
                content = b.get("content", "")
                if "green" in props.get("backgroundColor", "") and props.get("icon") == "✅" and "reorganized" in content.lower():
                    green_callout_found = True
                    break
    
        if not green_callout_found:
            errors.append("[X] Green callout with ✅ and reorganization message not found")
        else:
            checks_passed.append("[C] Green callout with ✅ and reorganization message found")
    
        return TaskScore(
            score=1.0 if len(errors) == 0 else 0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

    # Task Registry
    except Exception as e:
        logging.error(f"Runtime error in validation: {e}")
        return TaskScore(
            score=0.0,
            metadata=ScoreMetadata(
                success_accumulator=list(dict.fromkeys(checks_passed)),
                error_accumulator=list(dict.fromkeys(errors)),
            )
        )

# ==============================================================================
# Maps function names to themselves for easy lookup

REWARD_FUNCTIONS_NOTION_V2: Dict[str, Callable[[Backend, Dict[str, Any]], Tuple[float, str]]] = {
    "template-library-reorganization": _validate_template_library_reorganization,
    "template-cleanup-library": _validate_template_cleanup_library,
    "knowledge-sharing-system": _validate_knowledge_sharing_system,
    "projects-hub-organization": _validate_projects_hub_organization,
    "documentation-center-organization": _validate_documentation_center_organization,
    "documentation-template": _validate_documentation_template,
    "documentation-hub-setup": _validate_documentation_hub_setup,
    "project-hub-2024": _validate_project_hub_2024,
    "research-repository": _validate_research_repository,
    "project-planning-center": _validate_project_planning_center,
    "learning-development-hub": _validate_learning_development_hub,
    "product-documentation-suite": _validate_product_documentation_suite,
    "engineering-wiki-consolidation": _validate_engineering_wiki_consolidation,
    "development-priorities": _validate_development_priorities,
    "weekly-sprint-dashboard": _validate_weekly_sprint_dashboard,
    "engineering-wiki-content-enhancement": _validate_engineering_wiki_content_enhancement,
    "meeting-notes-archive-summary": _validate_meeting_notes_archive_summary,
    "company-handbook-reorganization": _validate_company_handbook_reorganization,
    "bug-tracking-summary-report": _validate_bug_tracking_summary_report,
    "architecture-overview": _validate_architecture_overview,
    "team-productivity-dashboard": _validate_team_productivity_dashboard,
    "bug-tracker-conditional-formatting": _validate_bug_tracker_conditional_formatting,
    "weekly-standup-design-review": _validate_weekly_standup_design_review,
    "sprint-metrics-action-items": _validate_sprint_metrics_action_items,
    "weekly-progress-metrics": _validate_weekly_progress_metrics,
    "sprint-retrospective-analysis": _validate_sprint_retrospective_analysis,
    "sprint-summary-dashboard": _validate_sprint_summary_dashboard,
    "bug-tracker-comprehensive-analysis": _validate_bug_tracker_comprehensive_analysis,
    "team-directory-devops": _validate_team_directory_devops,
    "code-examples-code-index": _validate_code_examples_code_index,
    "engineering-wiki-table-of-contents": _validate_engineering_wiki_table_of_contents,
    "external-resources-swap-sections": _validate_external_resources_swap_sections,
    "team-retrospective-action-items": _validate_team_retrospective_action_items,
    "external-resources-hub-transformation": _validate_external_resources_hub_transformation,
    "external-resources-reorganization": _validate_external_resources_reorganization,
    "feature-requests-priority-reorganization": _validate_feature_requests_priority_reorganization,
    "api-documentation-restructuring": _validate_api_documentation_restructuring,
    "company-handbook-swap-values-benefits": _validate_company_handbook_swap_values_benefits,
    "project-documentation-multilevel-analysis": _validate_project_documentation_multilevel_analysis,
    "external-resources-bookmarks-callout": _validate_external_resources_bookmarks_callout,
    "q4-planning-summary": _validate_q4_planning_summary,
    "design-system-component-inventory": _validate_design_system_component_inventory,
    "feature-requests-advanced-prioritization": _validate_feature_requests_advanced_prioritization,
    "weekly-standup-weekly-focus-areas": _validate_weekly_standup_weekly_focus_areas,
    "onboarding-guide-checklist": _validate_onboarding_guide_checklist,
    "code-examples-devops-section": _validate_code_examples_devops_section,
    "research-notes-progress-tracker": _validate_research_notes_progress_tracker,
    "design-system-component-tracking": _validate_design_system_component_tracking,
    "bug-tracker-priority-swap": _validate_bug_tracker_priority_swap,
    "weekly-standup-action-items-tracking": _validate_weekly_standup_action_items_tracking,
    "product-requirements-section-timestamps": _validate_product_requirements_section_timestamps,
    "api-documentation-endpoints-reorganization": _validate_api_documentation_endpoints_reorganization,
    "getting-started-task-analysis": _validate_getting_started_task_analysis,
    "code-examples-rust-section": _validate_code_examples_rust_section,
    "code-examples-ruby-section": _validate_code_examples_ruby_section,
    "team-directory-new-member": _validate_team_directory_new_member,
    "project-documentation-reorganization": _validate_project_documentation_reorganization,
    "external-resources-categorization": _validate_external_resources_categorization,
    "bug-tracker-mobile-priority": _validate_bug_tracker_mobile_priority,
    "feature-requests-pending-review": _validate_feature_requests_pending_review,
    "team-directory-image-reorg": _validate_team_directory_image_reorg,
    "workspace-intelligence-report": _validate_workspace_intelligence_report,
    "documentation-audit-report": _validate_documentation_audit_report,
    "team-organization-chart": _validate_team_organization_chart,
    "team-directory-analytics": _validate_team_directory_analytics,
    "weekly-standup-callout-insert": _validate_weekly_standup_callout_insert,
    "bug-tracker-status-reorganization": _validate_bug_tracker_status_reorganization,
    "documentation-index": _validate_documentation_index,
    "code-review-checklist": _validate_code_review_checklist,
    "code-examples-python-callout-typescript-bookmark": _validate_code_examples_python_callout_typescript_bookmark,
    "development-team-summary": _validate_development_team_summary,
    "todo-analytics-report": _validate_todo_analytics_report,
    "project-roadmap-strategic-priorities": _validate_project_roadmap_strategic_priorities,
    "q1-goals-progress-analysis": _validate_q1_goals_progress_analysis,
    "prd-overview-quote-todos": _validate_prd_overview_quote_todos,
    "onboarding-guide-quote-checklist": _validate_onboarding_guide_quote_checklist,
    "prd-swap-overview-sections": _validate_prd_swap_overview_sections,
    "code-examples-repository-statistics": _validate_code_examples_repository_statistics,
    "bug-tracker-priority-matrix": _validate_bug_tracker_priority_matrix,
    "project-guidelines-performance": _validate_project_guidelines_performance,
    "prd-technical-specifications": _validate_prd_technical_specifications,
    "sprint-planning-followup-schedule": _validate_sprint_planning_followup_schedule,
    "prd-performance-callout": _validate_prd_performance_callout,
    "engineering-wiki-swap-sections": _validate_engineering_wiki_swap_sections,
    "sprint-planning-velocity-tracking": _validate_sprint_planning_velocity_tracking,
    "weekly-standup-template-action-items": _validate_weekly_standup_template_action_items,
    "getting-started-progress-tracker": _validate_getting_started_progress_tracker,
    "brand-guidelines-move": _validate_brand_guidelines_move,
    "onboarding-guide-restructure-toc": _validate_onboarding_guide_restructure_toc,
    "architecture-overview-engineering-wiki": _validate_architecture_overview_engineering_wiki,
    "onboarding-guide-milestones": _validate_onboarding_guide_milestones,
    "project-guidelines-quick-reference": _validate_project_guidelines_quick_reference,
    "_validate_agent_reorganize_engineering_documentation": _validate_agent_reorganize_engineering_documentation,
    "_validate_agent_create_documentation_center_hub": _validate_agent_create_documentation_center_hub,
    "_validate_agent_create_knowledge_base_hub": _validate_agent_create_knowledge_base_hub,
    "_validate_agent_create_template_library": _validate_agent_create_template_library,
    "_validate_agent_create_meeting_notes_template_2025": _validate_agent_create_meeting_notes_template_2025,
    "_validate_agent_streamline_meeting_documentation": _validate_agent_streamline_meeting_documentation,
    "_validate_agent_reorganize_meeting_notes_structure": _validate_agent_reorganize_meeting_notes_structure,
    "_validate_agent_create_meeting_archive_2024": _validate_agent_create_meeting_archive_2024,
    "_validate_agent_consolidate_meeting_notes": _validate_agent_consolidate_meeting_notes,
    "_validate_agent_create_sprint_kickoff_template": _validate_agent_create_sprint_kickoff_template,
    "_validate_agent_create_team_onboarding_guide": _validate_agent_create_team_onboarding_guide,
    "_validate_agent_create_developer_onboarding_hub": _validate_agent_create_developer_onboarding_hub,
    "_validate_agent_create_new_hire_checklist_template": _validate_agent_create_new_hire_checklist_template,
    "_validate_agent_create_project_management_hub": _validate_agent_create_project_management_hub,
    "_validate_agent_reorganize_project_documentation_by_activity": _validate_agent_reorganize_project_documentation_by_activity,
    "_validate_agent_create_guideline_categories_summary": _validate_agent_create_guideline_categories_summary,
    "_validate_agent_add_weekly_standup_progress_section": _validate_agent_add_weekly_standup_progress_section,
    "_validate_agent_reorganize_external_resources_sections": _validate_agent_reorganize_external_resources_sections,
    "_validate_agent_add_engineering_wiki_best_practices": _validate_agent_add_engineering_wiki_best_practices,
    "_validate_agent_add_handbook_professional_development": _validate_agent_add_handbook_professional_development,
    "_validate_agent_reorganize_handbook_values_benefits": _validate_agent_reorganize_handbook_values_benefits,
    "_validate_agent_add_getting_started_date_section": _validate_agent_add_getting_started_date_section,
    "_validate_agent_add_getting_started_progress_tracking": _validate_agent_add_getting_started_progress_tracking,
    "_validate_agent_consolidate_project_guidelines_callouts": _validate_agent_consolidate_project_guidelines_callouts,
    "_validate_agent_create_feature_development_tracker": _validate_agent_create_feature_development_tracker,
    "_validate_agent_reorganize_engineering_wiki_sections": _validate_agent_reorganize_engineering_wiki_sections,
    "_validate_agent_add_feature_requests_in_development": _validate_agent_add_feature_requests_in_development,
    "_validate_agent_add_prd_overview_critical_updates": _validate_agent_add_prd_overview_critical_updates,
    "_validate_agent_create_design_system_resources": _validate_agent_create_design_system_resources,
    "_validate_agent_add_bug_tracker_in_progress": _validate_agent_add_bug_tracker_in_progress,
    "_validate_agent_add_getting_started_checklist_items": _validate_agent_add_getting_started_checklist_items,
    "_validate_agent_add_sprint_velocity_calculation": _validate_agent_add_sprint_velocity_calculation,
    "_validate_agent_create_documentation_index": _validate_agent_create_documentation_index,
    "_validate_agent_reorganize_onboarding_add_milestones": _validate_agent_reorganize_onboarding_add_milestones,
    "_validate_agent_add_sprint_planning_priority_tasks": _validate_agent_add_sprint_planning_priority_tasks,
    "_validate_agent_add_api_authentication_methods": _validate_agent_add_api_authentication_methods,
    "_validate_agent_add_code_examples_go_section": _validate_agent_add_code_examples_go_section,
    "_validate_agent_add_handbook_navigation_system": _validate_agent_add_handbook_navigation_system,
    "_validate_agent_add_onboarding_progress_tracking": _validate_agent_add_onboarding_progress_tracking,
    "_validate_agent_create_project_status_report": _validate_agent_create_project_status_report,
    "_validate_agent_add_api_documentation_footer": _validate_agent_add_api_documentation_footer,
    "_validate_agent_reorganize_external_resources_by_domain": _validate_agent_reorganize_external_resources_by_domain,
    "_validate_agent_add_prd_technical_architecture": _validate_agent_add_prd_technical_architecture,
    "_validate_agent_add_bug_tracker_security_section": _validate_agent_add_bug_tracker_security_section,
    "_validate_agent_add_prd_table_of_contents": _validate_agent_add_prd_table_of_contents,
    "_validate_agent_add_engineering_wiki_documentation_index": _validate_agent_add_engineering_wiki_documentation_index,
    "_validate_agent_add_weekly_standup_team_collaboration": _validate_agent_add_weekly_standup_team_collaboration,
    "_validate_agent_create_design_system_audit_page": _validate_agent_create_design_system_audit_page,
    "_validate_agent_add_design_system_style_guide": _validate_agent_add_design_system_style_guide,
    "_validate_agent_add_design_system_component_status": _validate_agent_add_design_system_component_status,
    "_validate_agent_add_onboarding_milestones_section": _validate_agent_add_onboarding_milestones_section,
    "_validate_agent_reorganize_handbook_swap_work_benefits": _validate_agent_reorganize_handbook_swap_work_benefits,
    "_validate_agent_reorganize_handbook_swap_values_benefits_add_remote": _validate_agent_reorganize_handbook_swap_values_benefits_add_remote,
    "_validate_agent_add_getting_started_troubleshooting": _validate_agent_add_getting_started_troubleshooting,
    "_validate_agent_create_onboarding_checklist_sibling": _validate_agent_create_onboarding_checklist_sibling,
    "_validate_agent_add_getting_started_advanced_features": _validate_agent_add_getting_started_advanced_features,
    "_validate_agent_add_bug_tracker_urgent_section": _validate_agent_add_bug_tracker_urgent_section,
    "_validate_agent_create_cross_project_task_tracker": _validate_agent_create_cross_project_task_tracker,
    "_validate_agent_enhance_onboarding_guide_comprehensive": _validate_agent_enhance_onboarding_guide_comprehensive,
    "_validate_agent_add_sprint_planning_commitment_summary": _validate_agent_add_sprint_planning_commitment_summary,
    "_validate_agent_add_engineering_wiki_quick_start": _validate_agent_add_engineering_wiki_quick_start,
    "_validate_agent_add_getting_started_time_estimates": _validate_agent_add_getting_started_time_estimates,
    "_validate_agent_add_team_retrospective_action_tracking": _validate_agent_add_team_retrospective_action_tracking,
    "_validate_agent_create_engineering_standards_child": _validate_agent_create_engineering_standards_child,
    "_validate_agent_reorganize_engineering_wiki_sections_swap": _validate_agent_reorganize_engineering_wiki_sections_swap,
    "_validate_agent_add_engineering_wiki_tool_integration": _validate_agent_add_engineering_wiki_tool_integration,
    "_validate_agent_add_weekly_standup_next_week_priorities": _validate_agent_add_weekly_standup_next_week_priorities,
    "_validate_agent_add_engineering_wiki_api_versioning": _validate_agent_add_engineering_wiki_api_versioning,
    "_validate_agent_create_roadmap_summary_2024": _validate_agent_create_roadmap_summary_2024,
    "_validate_agent_add_sprint_planning_metrics_analysis": _validate_agent_add_sprint_planning_metrics_analysis,
    "_validate_agent_create_style_guide_callout_reference": _validate_agent_create_style_guide_callout_reference,
    "_validate_agent_reorganize_handbook_swap_values_benefits_add_culture": _validate_agent_reorganize_handbook_swap_values_benefits_add_culture,
    "_validate_agent_create_component_library_interactive_catalog": _validate_agent_create_component_library_interactive_catalog,
    "_validate_agent_add_weekly_standup_date_header_todos": _validate_agent_add_weekly_standup_date_header_todos,
    "_validate_agent_create_documentation_quality_report": _validate_agent_create_documentation_quality_report,
    "_validate_agent_reorganize_architecture_create_legacy_archive": _validate_agent_reorganize_architecture_create_legacy_archive,
    "_validate_agent_add_code_examples_python_memoize_typescript_tip": _validate_agent_add_code_examples_python_memoize_typescript_tip,
    "_validate_agent_create_team_dashboard_meeting_aggregation": _validate_agent_create_team_dashboard_meeting_aggregation,
    "_validate_agent_add_sprint_planning_risk_assessment": _validate_agent_add_sprint_planning_risk_assessment,
    "_validate_agent_create_documentation_health_check": _validate_agent_create_documentation_health_check,
    "_validate_agent_add_engineering_wiki_api_documentation_standards": _validate_agent_add_engineering_wiki_api_documentation_standards,
    "_validate_agent_create_project_documentation_navigation_system": _validate_agent_create_project_documentation_navigation_system,
    "_validate_agent_add_project_guidelines_coverage_metrics": _validate_agent_add_project_guidelines_coverage_metrics,
    "_validate_agent_create_advanced_search_analytics": _validate_agent_create_advanced_search_analytics,
    "_validate_agent_create_workspace_analytics_coverage_report": _validate_agent_create_workspace_analytics_coverage_report,
    "_validate_agent_add_bug_tracker_date_header_updates": _validate_agent_add_bug_tracker_date_header_updates,
    "_validate_agent_add_design_system_component_guidelines": _validate_agent_add_design_system_component_guidelines,
    "_validate_agent_reorganize_onboarding_guide_h3_sections": _validate_agent_reorganize_onboarding_guide_h3_sections,
    "_validate_agent_create_workspace_navigation_guide": _validate_agent_create_workspace_navigation_guide,
    "_validate_agent_create_q1_sprint_retrospective_analysis": _validate_agent_create_q1_sprint_retrospective_analysis,
    "_validate_agent_add_product_roadmap_image_priorities_milestones": _validate_agent_add_product_roadmap_image_priorities_milestones,
    "_validate_agent_add_getting_started_conditional_callouts": _validate_agent_add_getting_started_conditional_callouts,
    "_validate_agent_add_engineering_wiki_dev_setup_security": _validate_agent_add_engineering_wiki_dev_setup_security,
    "_validate_agent_reorganize_handbook_swap_values_benefits_add_office_hours": _validate_agent_reorganize_handbook_swap_values_benefits_add_office_hours,
    "_validate_company_handbook_quick_navigation": _validate_company_handbook_quick_navigation,
    "_validate_agent_duplicate_onboarding_checklist": _validate_agent_duplicate_onboarding_checklist,
    "_validate_agent_reorganize_project_documentation": _validate_agent_reorganize_project_documentation,
    "_validate_agent_create_learning_development_hub": _validate_agent_create_learning_development_hub,
    "_validate_agent_create_quarterly_review_system": _validate_agent_create_quarterly_review_system,
    "_validate_agent_add_development_tools_section": _validate_agent_add_development_tools_section,
    "_validate_agent_update_standup_template_with_priorities": _validate_agent_update_standup_template_with_priorities,
    "_validate_agent_reorganize_external_resources": _validate_agent_reorganize_external_resources,
    "_validate_agent_add_react_examples_section": _validate_agent_add_react_examples_section,
    "_validate_agent_create_architecture_decision_records": _validate_agent_create_architecture_decision_records,
    "_validate_agent_create_project_health_dashboard": _validate_agent_create_project_health_dashboard,
    "_validate_agent_add_bug_tracker_date_section": _validate_agent_add_bug_tracker_date_section,
    "_validate_agent_add_code_review_checklist": _validate_agent_add_code_review_checklist,
    "_validate_agent_create_architecture_documentation_hub": _validate_agent_create_architecture_documentation_hub,
    "_validate_agent_add_first_day_tasks_time_estimates": _validate_agent_add_first_day_tasks_time_estimates,
    "_validate_agent_add_high_urgency_issues_section": _validate_agent_add_high_urgency_issues_section,
    "_validate_agent_create_product_launch_tracker": _validate_agent_create_product_launch_tracker,
    "_validate_agent_reorganize_company_handbook": _validate_agent_reorganize_company_handbook,
    "_validate_agent_create_external_resources_audit_report": _validate_agent_create_external_resources_audit_report,
    "_validate_agent_add_q1_goals_progress_update": _validate_agent_add_q1_goals_progress_update,
    "_validate_agent_add_30_day_milestone_checklist": _validate_agent_add_30_day_milestone_checklist,
    "_validate_agent_modify_project_guidelines_callouts": _validate_agent_modify_project_guidelines_callouts,
    "_validate_agent_create_feature_tracking_system": _validate_agent_create_feature_tracking_system,
    "_validate_agent_swap_prd_sections": _validate_agent_swap_prd_sections,
    "_validate_agent_add_sprint_goals_alignment_section": _validate_agent_add_sprint_goals_alignment_section,
    "_validate_agent_add_quarterly_milestones_section": _validate_agent_add_quarterly_milestones_section,
    "_validate_agent_create_feature_request_pipeline": _validate_agent_create_feature_request_pipeline,
    "_validate_agent_add_guidelines_review_todos": _validate_agent_add_guidelines_review_todos,
    "_validate_agent_add_api_version_tracking": _validate_agent_add_api_version_tracking,
    "_validate_agent_create_engineering_metrics_report": _validate_agent_create_engineering_metrics_report,
    "_validate_agent_insert_risk_assessment_section": _validate_agent_insert_risk_assessment_section,
    "_validate_agent_create_documentation_hierarchy_report": _validate_agent_create_documentation_hierarchy_report,
    "_validate_agent_insert_content_in_onboarding_guide": _validate_agent_insert_content_in_onboarding_guide,
    "_validate_agent_insert_infrastructure_section": _validate_agent_insert_infrastructure_section,
    "_validate_agent_reorganize_product_specs_page": _validate_agent_reorganize_product_specs_page,
    "_validate_agent_create_three_child_pages_under_engineering_wiki": _validate_agent_create_three_child_pages_under_engineering_wiki,
    "_validate_agent_swap_overview_and_user_stories_sections": _validate_agent_swap_overview_and_user_stories_sections,
    "_validate_agent_reorganize_design_system_page": _validate_agent_reorganize_design_system_page,
    "_validate_agent_add_meeting_analytics_to_sprint_planning": _validate_agent_add_meeting_analytics_to_sprint_planning,
    "_validate_agent_reorganize_project_guidelines_callouts_2": _validate_agent_reorganize_project_guidelines_callouts_2,
    "_validate_agent_team_directory_contact_system": _validate_agent_team_directory_contact_system,
    "_validate_agent_engineering_wiki_reorganization": _validate_agent_engineering_wiki_reorganization,
    "_validate_agent_getting_started_comprehensive_update": _validate_agent_getting_started_comprehensive_update,
    "_validate_agent_workspace_overview_dashboard": _validate_agent_workspace_overview_dashboard,
    "_validate_agent_getting_started_enhanced_onboarding": _validate_agent_getting_started_enhanced_onboarding,
    "_validate_agent_company_handbook_navigation_hub": _validate_agent_company_handbook_navigation_hub,
    "_validate_agent_documentation_health_check": _validate_agent_documentation_health_check,
    "_validate_agent_getting_started_resources": _validate_agent_getting_started_resources,
    "_validate_agent_engineering_standards": _validate_agent_engineering_standards,
    "_validate_agent_project_roadmap_reorganization": _validate_agent_project_roadmap_reorganization,
    "_validate_agent_design_system_color_palette": _validate_agent_design_system_color_palette,
    "_validate_agent_external_resources_link_report": _validate_agent_external_resources_link_report,
    "_validate_agent_feature_requests_voting_system": _validate_agent_feature_requests_voting_system,
    "_validate_agent_engineering_wiki_api_endpoints": _validate_agent_engineering_wiki_api_endpoints,
    "_validate_agent_meeting_notes_index": _validate_agent_meeting_notes_index,
    "_validate_agent_deployment_readiness_dashboard": _validate_agent_deployment_readiness_dashboard,
    "_validate_agent_prd_callout_implementation_roadmap": _validate_agent_prd_callout_implementation_roadmap,
    "_validate_agent_prd_surgical_modifications": _validate_agent_prd_surgical_modifications,
    "_validate_agent_prd_technical_specifications_2": _validate_agent_prd_technical_specifications_2,
    "_validate_agent_project_documentation_toc": _validate_agent_project_documentation_toc,
    "_validate_agent_reorganize_onboarding_guide_structure": _validate_agent_reorganize_onboarding_guide_structure,
    "_validate_agent_add_bug_analysis_dashboard": _validate_agent_add_bug_analysis_dashboard,
    "_validate_agent_duplicate_standup_section_with_progress": _validate_agent_duplicate_standup_section_with_progress,
    "_validate_agent_add_sprint_metrics_section": _validate_agent_add_sprint_metrics_section,
    "_validate_agent_organize_archived_content": _validate_agent_organize_archived_content,
    "_validate_agent_create_team_onboarding_hub": _validate_agent_create_team_onboarding_hub,
    "_validate_agent_create_onboarding_hub_with_duplicated_template": _validate_agent_create_onboarding_hub_with_duplicated_template,
    "_validate_agent_identify_sparse_content_pages": _validate_agent_identify_sparse_content_pages,
    "_validate_agent_organize_meeting_archive": _validate_agent_organize_meeting_archive,
    "_validate_agent_add_ruby_section_to_code_examples": _validate_agent_add_ruby_section_to_code_examples,
    "_validate_agent_create_project_management_hub_2": _validate_agent_create_project_management_hub_2,
    "_validate_agent_create_retrospective_workflow": _validate_agent_create_retrospective_workflow,
    "_validate_agent_create_content_archive_system": _validate_agent_create_content_archive_system,
    "_validate_agent_add_guideline_callouts_sequence": _validate_agent_add_guideline_callouts_sequence,
    "_validate_agent_add_java_section_to_code_examples": _validate_agent_add_java_section_to_code_examples,
    "_validate_agent_create_project_metrics_dashboard": _validate_agent_create_project_metrics_dashboard,
    "_validate_agent_add_followup_tasks_to_sprint_planning": _validate_agent_add_followup_tasks_to_sprint_planning,
    "_validate_agent_reorganize_company_handbook_2": _validate_agent_reorganize_company_handbook_2,
    "_validate_agent_reorganize_external_resources_2": _validate_agent_reorganize_external_resources_2,
    "_validate_agent_add_friday_tasks_to_standup": _validate_agent_add_friday_tasks_to_standup,
    "_validate_agent_reorganize_feature_requests_priority": _validate_agent_reorganize_feature_requests_priority,
    "_validate_agent_create_engineering_metrics_dashboard": _validate_agent_create_engineering_metrics_dashboard,
    "_validate_agent_create_q1_sprint_analysis": _validate_agent_create_q1_sprint_analysis,
    "_validate_agent_add_high_priority_bug_section": _validate_agent_add_high_priority_bug_section,
    "_validate_agent_add_time_allocation_to_standup": _validate_agent_add_time_allocation_to_standup,
    "_validate_agent_add_acceptance_criteria_section": _validate_agent_add_acceptance_criteria_section,
    "_validate_agent_add_remote_work_policy_to_handbook": _validate_agent_add_remote_work_policy_to_handbook,
    "_validate_agent_create_architecture_documentation_hub_2": _validate_agent_create_architecture_documentation_hub_2,
    "_validate_agent_create_engineering_wiki_index": _validate_agent_create_engineering_wiki_index,
    "_validate_agent_add_language_statistics_to_code_examples": _validate_agent_add_language_statistics_to_code_examples,
    "_validate_agent_create_comprehensive_engineering_metrics_dashboard": _validate_agent_create_comprehensive_engineering_metrics_dashboard,
    "_validate_agent_create_meeting_analytics_section": _validate_agent_create_meeting_analytics_section,
    "_validate_agent_reorganize_project_documentation_2": _validate_agent_reorganize_project_documentation_2,
    "_validate_agent_create_weekly_planning_dashboard": _validate_agent_create_weekly_planning_dashboard,
    "_validate_agent_create_feature_requests_prioritization_system": _validate_agent_create_feature_requests_prioritization_system,
    "_validate_agent_add_progress_tracker_to_onboarding_guide": _validate_agent_add_progress_tracker_to_onboarding_guide,
    "_validate_agent_restructure_engineering_wiki_with_navigation": _validate_agent_restructure_engineering_wiki_with_navigation,
    "_validate_agent_add_revision_history_to_prd": _validate_agent_add_revision_history_to_prd,
    "_validate_agent_add_executive_summary_to_prd": _validate_agent_add_executive_summary_to_prd,
    "_validate_agent_add_weekly_metrics_to_standup": _validate_agent_add_weekly_metrics_to_standup,
    "_validate_agent_create_project_roadmap_analytics": _validate_agent_create_project_roadmap_analytics,
    "_validate_agent_add_mobile_user_stories_to_prd": _validate_agent_add_mobile_user_stories_to_prd,
    "_validate_agent_create_code_review_standards": _validate_agent_create_code_review_standards,
    "_validate_agent_create_development_workflow_guide": _validate_agent_create_development_workflow_guide,
    "_validate_agent_create_quarterly_roadmap_tracker": _validate_agent_create_quarterly_roadmap_tracker,
    "_validate_agent_add_priority_callouts_to_user_stories": _validate_agent_add_priority_callouts_to_user_stories,
    "_validate_agent_add_sprint_commitment_and_metrics_task": _validate_agent_add_sprint_commitment_and_metrics_task,
    "_validate_agent_create_component_library_audit": _validate_agent_create_component_library_audit,
    "_validate_agent_add_structural_analysis_to_prd": _validate_agent_add_structural_analysis_to_prd,
    "_validate_agent_add_time_estimates_to_sprint_todos": _validate_agent_add_time_estimates_to_sprint_todos,
    "_validate_agent_create_project_health_dashboard_2": _validate_agent_create_project_health_dashboard_2,
    "_validate_agent_create_integrated_project_analytics": _validate_agent_create_integrated_project_analytics,
    "_validate_agent_update_getting_started_quick_start_progress": _validate_agent_update_getting_started_quick_start_progress,
    "_validate_agent_add_bug_analysis_dashboard_2": _validate_agent_add_bug_analysis_dashboard_2,
    "_validate_agent_modify_onboarding_guide_first_week_goals": _validate_agent_modify_onboarding_guide_first_week_goals,
    "_validate_agent_add_week_january_22_to_standup_template": _validate_agent_add_week_january_22_to_standup_template,
    "_validate_agent_add_code_review_checklist_to_engineering_wiki": _validate_agent_add_code_review_checklist_to_engineering_wiki,
    "_validate_agent_add_security_implementation_checklist": _validate_agent_add_security_implementation_checklist,
    "_validate_agent_create_engineering_best_practices_page": _validate_agent_create_engineering_best_practices_page,
    "_validate_agent_add_code_quality_report_to_code_examples": _validate_agent_add_code_quality_report_to_code_examples,
    "_validate_agent_create_team_performance_analytics": _validate_agent_create_team_performance_analytics,
    "_validate_agent_add_sprint_blockers_to_standup": _validate_agent_add_sprint_blockers_to_standup,
    "_validate_agent_reorganize_external_resources_by_domain_2": _validate_agent_reorganize_external_resources_by_domain_2,
    "_validate_agent_add_complex_update_to_standup": _validate_agent_add_complex_update_to_standup,
    "_validate_agent_create_code_examples_summary": _validate_agent_create_code_examples_summary,
    "_validate_agent_create_sprint_planning_archive": _validate_agent_create_sprint_planning_archive,
    "_validate_agent_create_meeting_analytics_dashboard": _validate_agent_create_meeting_analytics_dashboard,
    "_validate_agent_add_priority_matrix_to_feature_requests": _validate_agent_add_priority_matrix_to_feature_requests,
    "_validate_agent_add_document_index_to_architecture": _validate_agent_add_document_index_to_architecture,
    "_validate_agent_add_performance_requirements_to_prd": _validate_agent_add_performance_requirements_to_prd,
    "_validate_agent_add_implementation_timeline_to_prd": _validate_agent_add_implementation_timeline_to_prd,
    "_validate_agent_reorganize_bug_tracker_by_status": _validate_agent_reorganize_bug_tracker_by_status,
    "_validate_agent_create_task_analytics_dashboard": _validate_agent_create_task_analytics_dashboard,
    "_validate_agent_add_sprint_analysis_to_sprint_planning": _validate_agent_add_sprint_analysis_to_sprint_planning,
    "_validate_agent_create_habit_tracker_weekly_planning": _validate_agent_create_habit_tracker_weekly_planning,
    "_validate_agent_reorganize_company_handbook_complex": _validate_agent_reorganize_company_handbook_complex,
    "_validate_agent_add_task_distribution_to_sprint_planning": _validate_agent_add_task_distribution_to_sprint_planning,
    "_validate_agent_create_documentation_analytics_dashboard": _validate_agent_create_documentation_analytics_dashboard,
    "_validate_agent_create_consolidated_roadmap": _validate_agent_create_consolidated_roadmap,
    "_validate_agent_create_feature_request_dashboard": _validate_agent_create_feature_request_dashboard,
    "_validate_agent_reorganize_design_system": _validate_agent_reorganize_design_system,
    "_validate_agent_add_day_2_3_objectives_to_onboarding": _validate_agent_add_day_2_3_objectives_to_onboarding,
    "_validate_agent_reorganize_external_resources_swap": _validate_agent_reorganize_external_resources_swap,
    "_validate_agent_add_design_ux_updates_to_standup": _validate_agent_add_design_ux_updates_to_standup,
    "_validate_agent_add_performance_reviews_to_handbook": _validate_agent_add_performance_reviews_to_handbook,
    "_validate_agent_create_weekly_planning_dashboard_child": _validate_agent_create_weekly_planning_dashboard_child,
    "_validate_agent_reorganize_company_handbook_complete": _validate_agent_reorganize_company_handbook_complete,
    "_validate_agent_create_architecture_coverage_report": _validate_agent_create_architecture_coverage_report,
    "_validate_agent_create_quarterly_report_summary": _validate_agent_create_quarterly_report_summary,
    "_validate_agent_add_implementation_roadmap_to_feature_requests": _validate_agent_add_implementation_roadmap_to_feature_requests,
    "_validate_agent_add_quick_start_checklist_to_onboarding": _validate_agent_add_quick_start_checklist_to_onboarding,
    "_validate_agent_add_progressive_disclosure_to_onboarding": _validate_agent_add_progressive_disclosure_to_onboarding,
    "_validate_agent_audit_project_documentation_comprehensive": _validate_agent_audit_project_documentation_comprehensive,
    "_validate_agent_add_code_quality_standards_to_code_examples": _validate_agent_add_code_quality_standards_to_code_examples,
    "_validate_agent_add_development_best_practices_to_guidelines": _validate_agent_add_development_best_practices_to_guidelines,
    "_validate_agent_add_engineering_team_members_to_directory": _validate_agent_add_engineering_team_members_to_directory,
    "_validate_agent_create_quarterly_goals_tracker_root": _validate_agent_create_quarterly_goals_tracker_root,
    "_validate_agent_add_team_statistics_to_directory": _validate_agent_add_team_statistics_to_directory,
    "_validate_agent_add_callout_usage_statistics_to_guidelines": _validate_agent_add_callout_usage_statistics_to_guidelines,
    "_validate_agent_add_technical_debt_items_to_sprint_planning": _validate_agent_add_technical_debt_items_to_sprint_planning,
    "_validate_agent_create_meeting_notes_archive_summary": _validate_agent_create_meeting_notes_archive_summary,
    "_validate_agent_create_project_hub": _validate_agent_create_project_hub,
    "_validate_agent_create_team_feedback_hub": _validate_agent_create_team_feedback_hub,
    "_validate_agent_create_archive_management": _validate_agent_create_archive_management,
    "_validate_agent_create_team_resource_hub": _validate_agent_create_team_resource_hub,
    "_validate_agent_create_templates_collection": _validate_agent_create_templates_collection,
    "_validate_agent_create_knowledge_base": _validate_agent_create_knowledge_base,
    "_validate_agent_create_engineering_knowledge_base": _validate_agent_create_engineering_knowledge_base,
    "_validate_weekly_onboarding_curriculum": _validate_weekly_onboarding_curriculum,
    "_validate_agent_create_knowledge_hub": _validate_agent_create_knowledge_hub,
    "_validate_agent_create_product_management_hub": _validate_agent_create_product_management_hub,
    "_validate_agent_create_training_library": _validate_agent_create_training_library,
    "_validate_agent_create_team_handbook": _validate_agent_create_team_handbook,
    "_validate_agent_create_design_system_docs": _validate_agent_create_design_system_docs,
    "_validate_agent_create_meeting_action_items_hub": _validate_agent_create_meeting_action_items_hub,
    "_validate_agent_create_technical_architecture_section": _validate_agent_create_technical_architecture_section,
    "_validate_agent_create_bug_tracker_security_section": _validate_agent_create_bug_tracker_security_section,
    "_validate_agent_create_sprint_progress_tracking": _validate_agent_create_sprint_progress_tracking,
    "_validate_agent_create_feature_requests_conversion": _validate_agent_create_feature_requests_conversion,
    "_validate_agent_create_prd_performance_requirements": _validate_agent_create_prd_performance_requirements,
    "_validate_agent_create_getting_started_onboarding_progress": _validate_agent_create_getting_started_onboarding_progress,
    "_validate_agent_create_company_handbook_recognition": _validate_agent_create_company_handbook_recognition,
    "_validate_agent_create_feature_requests_priority_reorganization": _validate_agent_create_feature_requests_priority_reorganization,
    "_validate_agent_create_documentation_audit_report": _validate_agent_create_documentation_audit_report,
    "_validate_agent_create_project_roadmap_swap": _validate_agent_create_project_roadmap_swap,
    "_validate_agent_create_engineering_dashboard": _validate_agent_create_engineering_dashboard,
    "_validate_agent_create_getting_started_learning_path": _validate_agent_create_getting_started_learning_path,
    "_validate_agent_create_bug_tracker_hot_fixes": _validate_agent_create_bug_tracker_hot_fixes,
    "_validate_agent_create_team_directory_employee_section": _validate_agent_create_team_directory_employee_section,
    "_validate_agent_create_project_health_dashboard_3": _validate_agent_create_project_health_dashboard_3,
    "_validate_agent_create_getting_started_date_header": _validate_agent_create_getting_started_date_header,
    "_validate_agent_create_weekly_standup_priority_updates": _validate_agent_create_weekly_standup_priority_updates,
    "_validate_agent_create_feature_requests_portal": _validate_agent_create_feature_requests_portal,
    "_validate_agent_create_project_goals_analysis": _validate_agent_create_project_goals_analysis,
    "_validate_agent_create_team_knowledge_base": _validate_agent_create_team_knowledge_base,
    "_validate_agent_create_code_examples_index": _validate_agent_create_code_examples_index,
    "_validate_agent_create_workspace_analytics_dashboard": _validate_agent_create_workspace_analytics_dashboard,
    "_validate_agent_create_sprint_retrospective_dashboard": _validate_agent_create_sprint_retrospective_dashboard,
    "_validate_weekly_standup_sprint_progress": _validate_weekly_standup_sprint_progress,
    "_validate_weekly_standup_performance_metrics": _validate_weekly_standup_performance_metrics,
    "_validate_sprint_planning_enhancement": _validate_sprint_planning_enhancement,
    "_validate_company_handbook_hybrid_work": _validate_company_handbook_hybrid_work,
    "_validate_project_guidelines_dividers": _validate_project_guidelines_dividers,
    "_validate_project_roadmap_swap_sections": _validate_project_roadmap_swap_sections,
    "_validate_api_documentation_versioning": _validate_api_documentation_versioning,
    "_validate_team_directory_cross_page": _validate_team_directory_cross_page,
    "_validate_project_status_summary": _validate_project_status_summary,
    "_validate_bug_tracker_analysis_section": _validate_bug_tracker_analysis_section,
    "_validate_code_examples_snippet_library": _validate_code_examples_snippet_library,
    "_validate_feature_requests_prioritization": _validate_feature_requests_prioritization,
    "_validate_code_examples_quick_navigation": _validate_code_examples_quick_navigation,
    "_validate_code_examples_python_section": _validate_code_examples_python_section,
    "_validate_company_handbook_swap_sections": _validate_company_handbook_swap_sections,
    "_validate_onboarding_guide_progress_tracker": _validate_onboarding_guide_progress_tracker,
    "_validate_project_guidelines_testing_section": _validate_project_guidelines_testing_section,
    "_validate_q1_progress_report": _validate_q1_progress_report,
    "_validate_getting_started_advanced_features": _validate_getting_started_advanced_features,
    "_validate_getting_started_date_header": _validate_getting_started_date_header,
    "_validate_weekly_standup_week_tracking": _validate_weekly_standup_week_tracking,
    "_validate_feature_requests_priority_system": _validate_feature_requests_priority_system,
    "_validate_add_advanced_tasks_to_getting_started": _validate_add_advanced_tasks_to_getting_started,
    "_validate_comprehensive_getting_started_update": _validate_comprehensive_getting_started_update,
    "_validate_feature_requests_prioritization_system": _validate_feature_requests_prioritization_system,
    "_validate_create_code_language_statistics": _validate_create_code_language_statistics,
    "_validate_design_system_documentation_audit": _validate_design_system_documentation_audit,
    "_validate_enhance_team_directory_structure": _validate_enhance_team_directory_structure,
    "_validate_prd_requirement_priorities_section": _validate_prd_requirement_priorities_section,
    "_validate_project_guidelines_navigation_guide": _validate_project_guidelines_navigation_guide,
    "_validate_add_react_examples_section_2": _validate_add_react_examples_section_2,
    "_validate_add_development_standards_section": _validate_add_development_standards_section,
    "_validate_code_repository_categorization_system": _validate_code_repository_categorization_system,
    "_validate_create_architecture_decision_records_2": _validate_create_architecture_decision_records_2,
    "_validate_create_daily_standup_tracker": _validate_create_daily_standup_tracker,
    "_validate_feature_requests_quarterly_planning": _validate_feature_requests_quarterly_planning,
    "_validate_team_directory_comprehensive_update": _validate_team_directory_comprehensive_update,
    "_validate_prd_table_of_contents": _validate_prd_table_of_contents,
    "_validate_weekly_standup_template_modification": _validate_weekly_standup_template_modification,
    "_validate_add_utility_functions_section": _validate_add_utility_functions_section,
    "_validate_prd_overview_statistics": _validate_prd_overview_statistics,
    "_validate_company_handbook_comprehensive_update": _validate_company_handbook_comprehensive_update,
    "_validate_onboarding_guide_modifications": _validate_onboarding_guide_modifications,
    "_validate_create_project_guidelines_audit": _validate_create_project_guidelines_audit,
    "_validate_engineering_wiki_troubleshooting": _validate_engineering_wiki_troubleshooting,
    "_validate_create_team_task_tracker": _validate_create_team_task_tracker,
    "_validate_sprint_planning_reorganization": _validate_sprint_planning_reorganization,
    "_validate_company_handbook_cross_referencing": _validate_company_handbook_cross_referencing,
    "_validate_engineering_wiki_development_workflow": _validate_engineering_wiki_development_workflow,
    "_validate_product_specifications_guidelines": _validate_product_specifications_guidelines,
    "_validate_create_development_roadmap": _validate_create_development_roadmap,
    "_validate_design_system_extended_palette": _validate_design_system_extended_palette,
    "_validate_company_handbook_section_swap": _validate_company_handbook_section_swap,
    "_validate_company_handbook_comprehensive_reorganization": _validate_company_handbook_comprehensive_reorganization,
    "_validate_external_resources_bookmark_analysis": _validate_external_resources_bookmark_analysis,
    "_validate_external_resources_learning_section": _validate_external_resources_learning_section,
    "_validate_feature_requests_priority_tracking": _validate_feature_requests_priority_tracking,
    "weekly-standup-weekly-archive": _validate_weekly_standup_weekly_archive,
    "weekly-standup-sprint-goals-section": _validate_weekly_standup_sprint_goals_section,
    "weekly-standup-focus-areas-analytics": _validate_weekly_standup_focus_areas_analytics,
    "weekly-standup-current-blockers": _validate_weekly_standup_current_blockers,
    "team-workload-analysis": _validate_team_workload_analysis,
    "sprint-planning-velocity-section": _validate_sprint_planning_velocity_section,
    "sprint-planning-updates-section": _validate_sprint_planning_updates_section,
    "sprint-planning-progress-metrics": _validate_sprint_planning_progress_metrics,
    "sprint-planning-analysis-section": _validate_sprint_planning_analysis_section,
    "project-status-dashboard": _validate_project_status_dashboard,
    "project-health-report-comprehensive": _validate_project_health_report_comprehensive,
    "project-health-dashboard": _validate_project_health_dashboard,
    "project-guidelines-callout-reorganization": _validate_project_guidelines_callout_reorganization,
    "product-specs-requirements-traceability": _validate_product_specs_requirements_traceability,
    "prd-technical-specifications-3": _validate_prd_technical_specifications_3,
    "prd-swap-overview-user-stories": _validate_prd_swap_overview_user_stories,
    "onboarding-guide-30-day-milestones": _validate_onboarding_guide_30_day_milestones,
    "meeting-notes-index-system": _validate_meeting_notes_index_system,
    "feature-requests-tracking-system": _validate_feature_requests_tracking_system,
    "feature-requests-priority-visualization": _validate_feature_requests_priority_visualization,
    "feature-requests-prioritization-matrix": _validate_feature_requests_prioritization_matrix,
    "feature-request-analytics": _validate_feature_request_analytics,
    "external-resources-complete-reorganization": _validate_external_resources_complete_reorganization,
    "engineering-wiki-swap-tech-setup": _validate_engineering_wiki_swap_tech_setup,
    "engineering-wiki-swap-and-enhance": _validate_engineering_wiki_swap_and_enhance,
    "engineering-wiki-security-tools": _validate_engineering_wiki_security_tools,
    "documentation-index-complete-map": _validate_documentation_index_complete_map,
    "design-system-typography": _validate_design_system_typography,
    "design-system-component-library-overview": _validate_design_system_component_library_overview,
    "design-system-component-documentation": _validate_design_system_component_documentation,
    "design-system-color-documentation": _validate_design_system_color_documentation,
    "create-team-task-tracker-2": _validate_create_team_task_tracker_2,
    "create-sprint-retrospective-dashboard-2": _validate_create_sprint_retrospective_dashboard_2,
    "create-online-resume": _validate_create_online_resume,
    "create-japan-travel-planner": _validate_create_japan_travel_planner,
    "create-engineering-documentation-hub": _validate_create_engineering_documentation_hub,
    "company-handbook-communication-guidelines": _validate_company_handbook_communication_guidelines,
    "code-examples-swap-sections": _validate_code_examples_swap_sections,
    "code-examples-rust-callout": _validate_code_examples_rust_callout,
    "bug-tracker-resolution-workflow": _validate_bug_tracker_resolution_workflow,
    "bug-tracker-priority-classification": _validate_bug_tracker_priority_classification,
    "bug-tracker-automated-analysis": _validate_bug_tracker_automated_analysis,
    "architecture-analysis": _validate_architecture_analysis,
    "api-documentation-testing-guide": _validate_api_documentation_testing_guide,
    "api-documentation-rate-limiting": _validate_api_documentation_rate_limiting,
    "api-documentation-error-handling": _validate_api_documentation_error_handling,
    "api-documentation-endpoints-security": _validate_api_documentation_endpoints_security,
    "_validate_agent_organise_project_planning_hub": _validate_agent_organise_project_planning_hub,
    "_validate_agent_create_documentation_structure": _validate_agent_create_documentation_structure,
    "_validate_agent_restructure_engineering_documentation": _validate_agent_restructure_engineering_documentation,
    "_validate_agent_consolidate_architecture_docs": _validate_agent_consolidate_architecture_docs,
    "_validate_agent_create_documentation_overview_map": _validate_agent_create_documentation_overview_map,
    "_validate_agent_create_meeting_analytics_hub": _validate_agent_create_meeting_analytics_hub,
    "_validate_agent_create_design_system_catalog": _validate_agent_create_design_system_catalog,
    "_validate_agent_add_document_structure_overview": _validate_agent_add_document_structure_overview,
    "_validate_agent_add_sprint_goals_alignment": _validate_agent_add_sprint_goals_alignment,
    "_validate_agent_reorganize_external_resources_3": _validate_agent_reorganize_external_resources_3,
    "_validate_agent_add_advanced_features_checklist": _validate_agent_add_advanced_features_checklist,
    "_validate_agent_create_team_performance_dashboard": _validate_agent_create_team_performance_dashboard,
    "_validate_agent_create_team_task_dashboard": _validate_agent_create_team_task_dashboard,
    "_validate_agent_reorganize_prd_overview_sections": _validate_agent_reorganize_prd_overview_sections,
    "_validate_agent_reorganize_feature_requests_by_status": _validate_agent_reorganize_feature_requests_by_status,
    "_validate_agent_transform_standup_template_dynamic": _validate_agent_transform_standup_template_dynamic,
    "_validate_agent_analyze_prd_content_metrics": _validate_agent_analyze_prd_content_metrics,
    "_validate_agent_add_onboarding_tracking_system": _validate_agent_add_onboarding_tracking_system,
    "_validate_agent_add_bug_resolution_statistics": _validate_agent_add_bug_resolution_statistics,
    "_validate_agent_add_sprint_velocity_metrics": _validate_agent_add_sprint_velocity_metrics,
    "_validate_agent_add_hot_fixes_section": _validate_agent_add_hot_fixes_section,
    "_validate_agent_reorganize_guidelines_by_color": _validate_agent_reorganize_guidelines_by_color,
    "_validate_agent_add_api_rate_limiting_section": _validate_agent_add_api_rate_limiting_section,
    "_validate_agent_create_meeting_analysis_report": _validate_agent_create_meeting_analysis_report,
    "_validate_agent_add_urgent_priority_section": _validate_agent_add_urgent_priority_section,
    "_validate_agent_add_utility_functions_section_2": _validate_agent_add_utility_functions_section_2,
    "_validate_agent_add_performance_reviews_section": _validate_agent_add_performance_reviews_section,
    "_validate_agent_create_architecture_summary_report": _validate_agent_create_architecture_summary_report,
    "_validate_agent_add_tutorial_enhancement_system": _validate_agent_add_tutorial_enhancement_system,
    "_validate_agent_add_advanced_patterns_section": _validate_agent_add_advanced_patterns_section,
    "_validate_agent_swap_api_sections_with_security": _validate_agent_swap_api_sections_with_security,
    "_validate_agent_reorganize_team_directory": _validate_agent_reorganize_team_directory,
    "_validate_agent_add_priority_markers_standup_template": _validate_agent_add_priority_markers_standup_template,
    "_validate_agent_create_code_quality_report": _validate_agent_create_code_quality_report,
    "_validate_agent_organize_feature_requests_dashboard": _validate_agent_organize_feature_requests_dashboard,
    "_validate_agent_add_meeting_analytics_dashboard": _validate_agent_add_meeting_analytics_dashboard,
    "_validate_agent_create_documentation_health_report": _validate_agent_create_documentation_health_report,
    "_validate_agent_enhance_sprint_planning_meeting": _validate_agent_enhance_sprint_planning_meeting,
    "_validate_agent_add_prd_executive_summary": _validate_agent_add_prd_executive_summary,
    "_validate_agent_add_sprint_metrics_section_2": _validate_agent_add_sprint_metrics_section_2,
    "_validate_agent_reorganize_company_handbook_3": _validate_agent_reorganize_company_handbook_3,
    "_validate_agent_create_meeting_archive_system": _validate_agent_create_meeting_archive_system,
    "_validate_agent_create_retrospective_analysis": _validate_agent_create_retrospective_analysis,
    "_validate_agent_add_language_statistics": _validate_agent_add_language_statistics,
    "_validate_agent_restructure_handbook_sections": _validate_agent_restructure_handbook_sections,
    "_validate_agent_add_advanced_features_section": _validate_agent_add_advanced_features_section,
    "_validate_agent_enhance_team_retrospective": _validate_agent_enhance_team_retrospective,
    "_validate_agent_create_workspace_activity_dashboard": _validate_agent_create_workspace_activity_dashboard,
    "_validate_agent_add_development_best_practices": _validate_agent_add_development_best_practices,
    "_validate_agent_add_react_examples_section_3": _validate_agent_add_react_examples_section_3,
    "_validate_agent_reorganize_handbook_with_performance": _validate_agent_reorganize_handbook_with_performance,
    "_validate_agent_add_code_examples_after_tips": _validate_agent_add_code_examples_after_tips,
    "_validate_agent_add_user_story_analysis": _validate_agent_add_user_story_analysis,
    "_validate_agent_add_sprint_metrics_kpis": _validate_agent_add_sprint_metrics_kpis,
    "_validate_agent_complex_handbook_reorganization": _validate_agent_complex_handbook_reorganization,
    "_validate_agent_cross_page_values_integration": _validate_agent_cross_page_values_integration,
    "_validate_agent_add_medium_priority_stats": _validate_agent_add_medium_priority_stats,
    "_validate_agent_add_handbook_update_tracking": _validate_agent_add_handbook_update_tracking,
    "_validate_agent_add_team_velocity_tracker": _validate_agent_add_team_velocity_tracker,
    "_validate_agent_create_goals_dashboard": _validate_agent_create_goals_dashboard,
    "_validate_agent_add_checklist_analysis": _validate_agent_add_checklist_analysis,
    "_validate_agent_create_team_productivity_report": _validate_agent_create_team_productivity_report,
    "_validate_agent_create_quarterly_health_report": _validate_agent_create_quarterly_health_report,
    "_validate_agent_create_onboarding_progress_tracker": _validate_agent_create_onboarding_progress_tracker,
    "_validate_agent_create_bug_triage_dashboard": _validate_agent_create_bug_triage_dashboard,
    "_validate_agent_add_team_directory_alumni": _validate_agent_add_team_directory_alumni,
    "_validate_agent_add_prd_document_navigation": _validate_agent_add_prd_document_navigation,
    "_validate_agent_add_handbook_quick_reference": _validate_agent_add_handbook_quick_reference,
    "_validate_agent_add_wiki_docker_setup": _validate_agent_add_wiki_docker_setup,
    "_validate_agent_add_python_examples_section": _validate_agent_add_python_examples_section,
    "_validate_agent_add_learning_platforms_resources": _validate_agent_add_learning_platforms_resources,
    "_validate_agent_add_mid_sprint_review_section": _validate_agent_add_mid_sprint_review_section,
    "_validate_agent_add_action_items_retrospective": _validate_agent_add_action_items_retrospective,
    "_validate_agent_enhance_onboarding_experience": _validate_agent_enhance_onboarding_experience,
    "_validate_agent_reorganize_standup_template": _validate_agent_reorganize_standup_template,
    "_validate_agent_create_resource_library_hub": _validate_agent_create_resource_library_hub,
    "_validate_agent_create_external_resources_audit": _validate_agent_create_external_resources_audit,
    "_validate_agent_add_product_team_section": _validate_agent_add_product_team_section,
    "_validate_agent_swap_wiki_sections_with_additions": _validate_agent_swap_wiki_sections_with_additions,
    "_validate_documentation_hub_creation": _validate_documentation_hub_creation,
    "_validate_project_tracking_system": _validate_project_tracking_system,
    "_validate_meeting_documentation_restructure": _validate_meeting_documentation_restructure,
    "_validate_onboarding_checklist_creation": _validate_onboarding_checklist_creation,
    "_validate_archive_organization": _validate_archive_organization,
    "_validate_project_reorganization": _validate_project_reorganization,
    "_validate_template_library_creation": _validate_template_library_creation,
    "_validate_comprehensive_documentation_structure": _validate_comprehensive_documentation_structure,
    "_validate_learning_and_development_hub": _validate_learning_and_development_hub,
    "_validate_team_onboarding_hub": _validate_team_onboarding_hub,
    "_validate_meeting_notes_reorganization": _validate_meeting_notes_reorganization,
    "_validate_project_planning_workspace": _validate_project_planning_workspace,
    "_validate_archive_organization_v2": _validate_archive_organization_v2,
    "_validate_roadmap_duplication_and_customization": _validate_roadmap_duplication_and_customization,
    "_validate_onboarding_hub_creation": _validate_onboarding_hub_creation,
    "_validate_knowledge_sharing_system": _validate_knowledge_sharing_system,
    "_validate_architecture_consolidation": _validate_architecture_consolidation,
    "_validate_design_system_hub_creation": _validate_design_system_hub_creation,
    "_validate_projects_hub_organization": _validate_projects_hub_organization,
    "_validate_engineering_documentation_restructure": _validate_engineering_documentation_restructure,
    "_validate_meeting_streamline": _validate_meeting_streamline,
    "_validate_project_tracking_system_v2": _validate_project_tracking_system_v2,
    "_validate_development_workflow_guide": _validate_development_workflow_guide,
    "_validate_sprint_kickoff_template": _validate_sprint_kickoff_template,
    "_validate_template_reorganization": _validate_template_reorganization,
    "_validate_archive_hub_organization": _validate_archive_hub_organization,
    "_validate_comprehensive_team_resource_center": _validate_comprehensive_team_resource_center,
    "_validate_quarterly_review_organization": _validate_quarterly_review_organization,
    "_validate_meeting_documentation_organization": _validate_meeting_documentation_organization,
    "_validate_project_management_setup": _validate_project_management_setup,
    "_validate_project_documentation_system": _validate_project_documentation_system,
    "_validate_team_retrospective_achievements_section": _validate_team_retrospective_achievements_section,
    "_validate_project_documentation_index": _validate_project_documentation_index,
    "_validate_agent_engineering_wiki_content_insertion": _validate_agent_engineering_wiki_content_insertion,
    "_validate_engineering_wiki_index": _validate_engineering_wiki_index,
    "_validate_getting_started_onboarding_checklist": _validate_getting_started_onboarding_checklist,
    "_validate_agent_favorite_pages_directory": _validate_agent_favorite_pages_directory,
    "_validate_agent_company_handbook_toc": _validate_agent_company_handbook_toc,
    "_validate_agent_project_roadmap_summary": _validate_agent_project_roadmap_summary,
    "_validate_agent_project_roadmap_reorganization_2": _validate_agent_project_roadmap_reorganization_2,
    "_validate_agent_content_lifecycle_management": _validate_agent_content_lifecycle_management,
    "_validate_agent_meeting_documentation_structure": _validate_agent_meeting_documentation_structure,
    "_validate_agent_workspace_orientation_guide": _validate_agent_workspace_orientation_guide,
    "_validate_agent_project_structure_copy": _validate_agent_project_structure_copy,
    "_validate_agent_project_task_analysis": _validate_agent_project_task_analysis,
    "_validate_agent_weekly_standup_time_sensitive": _validate_agent_weekly_standup_time_sensitive,
    "_validate_agent_code_examples_toc": _validate_agent_code_examples_toc,
    "_validate_agent_prd_section_summaries": _validate_agent_prd_section_summaries,
    "_validate_agent_documentation_index_2": _validate_agent_documentation_index_2,
    "_validate_agent_company_handbook_reorganization_2": _validate_agent_company_handbook_reorganization_2,
    "_validate_agent_meeting_analysis_report": _validate_agent_meeting_analysis_report,
    "_validate_agent_engineering_team_dashboard": _validate_agent_engineering_team_dashboard,
    "_validate_agent_prd_user_stories_priority_matrix": _validate_agent_prd_user_stories_priority_matrix,
    "_validate_agent_sprint_meeting_analytics": _validate_agent_sprint_meeting_analytics,
    "_validate_agent_weekly_standup_time_estimates": _validate_agent_weekly_standup_time_estimates,
    "_validate_agent_code_examples_reorganization": _validate_agent_code_examples_reorganization,
    "_validate_agent_project_health_dashboard_2": _validate_agent_project_health_dashboard_2,
    "_validate_agent_weekly_standup_week_statistics": _validate_agent_weekly_standup_week_statistics,
    "_validate_agent_prd_security_compliance": _validate_agent_prd_security_compliance,
    "_validate_agent_weekly_standup_next_week_plans": _validate_agent_weekly_standup_next_week_plans,
    "_validate_agent_product_localization_tracker": _validate_agent_product_localization_tracker,
    "_validate_agent_code_examples_performance_patterns": _validate_agent_code_examples_performance_patterns,
    "_validate_agent_code_review_standards": _validate_agent_code_review_standards,
    "_validate_agent_engineering_wiki_toc": _validate_agent_engineering_wiki_toc,
    "_validate_agent_marketing_campaign_planner": _validate_agent_marketing_campaign_planner,
    "_validate_agent_bug_tracker_status_summary": _validate_agent_bug_tracker_status_summary,
    "_validate_performance_guidelines_insertion": _validate_performance_guidelines_insertion,
    "_validate_agent_weekly_standup_in_progress_items": _validate_agent_weekly_standup_in_progress_items,
    "_validate_agent_bug_tracker_performance_issues": _validate_agent_bug_tracker_performance_issues,
    "_validate_engineering_wiki_documentation_coverage": _validate_engineering_wiki_documentation_coverage,
    "_validate_agent_engineering_resource_hub": _validate_agent_engineering_resource_hub,
    "_validate_agent_team_directory_skills_matrix": _validate_agent_team_directory_skills_matrix,
    "_validate_agent_feature_requests_analysis": _validate_agent_feature_requests_analysis,
    "_validate_agent_feature_backlog_analysis": _validate_agent_feature_backlog_analysis,
    "_validate_agent_project_documentation_architecture": _validate_agent_project_documentation_architecture,
    "_validate_agent_external_resources_analytics": _validate_agent_external_resources_analytics,
    "_validate_agent_feature_tracking_dashboard": _validate_agent_feature_tracking_dashboard,
    "_validate_agent_company_handbook_employee_resources": _validate_agent_company_handbook_employee_resources,
    "_validate_engineering_wiki_tool_versions": _validate_engineering_wiki_tool_versions,
    "_validate_agent_japan_travel_planner": _validate_agent_japan_travel_planner,
    "_validate_agent_weekly_standup_metrics_tracking": _validate_agent_weekly_standup_metrics_tracking,
    "_validate_agent_team_directory_org_chart": _validate_agent_team_directory_org_chart,
    "_validate_agent_sprint_retrospective_analysis_2": _validate_agent_sprint_retrospective_analysis_2,
    "_validate_agent_q1_q2_goals_comparison": _validate_agent_q1_q2_goals_comparison,
    "_validate_agent_weekly_standup_template_enhancement": _validate_agent_weekly_standup_template_enhancement,
    "_validate_agent_onboarding_checklist_generation": _validate_agent_onboarding_checklist_generation,
    "_validate_agent_project_status_dashboard": _validate_agent_project_status_dashboard,
    "_validate_agent_code_examples_advanced_python_patterns": _validate_agent_code_examples_advanced_python_patterns,
    "_validate_agent_external_resources_links_organization": _validate_agent_external_resources_links_organization,
    "_validate_agent_company_handbook_surgical_modifications": _validate_agent_company_handbook_surgical_modifications,
    "_validate_engineering_wiki_knowledge_base_index": _validate_engineering_wiki_knowledge_base_index,
    "_validate_agent_prd_document_structure": _validate_agent_prd_document_structure,
    "_validate_agent_workspace_analytics_hub": _validate_agent_workspace_analytics_hub,
    "_validate_agent_getting_started_todo_timeline_summary": _validate_agent_getting_started_todo_timeline_summary,
    "_validate_agent_architecture_overview_dashboard": _validate_agent_architecture_overview_dashboard,
    "_validate_engineering_wiki_advanced_content_analysis": _validate_engineering_wiki_advanced_content_analysis,
    "_validate_getting_started_key_features_content_insertion": _validate_getting_started_key_features_content_insertion,
    "_validate_agent_api_versioning_documentation": _validate_agent_api_versioning_documentation,
    "_validate_agent_company_handbook_policy_update": _validate_agent_company_handbook_policy_update,
    "_validate_agent_component_inventory_report": _validate_agent_component_inventory_report,
    "_validate_agent_company_handbook_culture_section": _validate_agent_company_handbook_culture_section,
    "_validate_agent_engineering_team_hub": _validate_agent_engineering_team_hub,
    "_validate_agent_engineering_team_summary": _validate_agent_engineering_team_summary,
    "_validate_agent_engineering_wiki_reorganize_enhance": _validate_agent_engineering_wiki_reorganize_enhance,
    "_validate_agent_feature_requests_backlog_transformation": _validate_agent_feature_requests_backlog_transformation,
    "_validate_agent_getting_started_checklist_callouts": _validate_agent_getting_started_checklist_callouts,
    "_validate_getting_started_quick_tips": _validate_getting_started_quick_tips,
    "_validate_agent_meeting_notes_templates_summary": _validate_agent_meeting_notes_templates_summary,
    "_validate_onboarding_guide_first_week_enhancement": _validate_onboarding_guide_first_week_enhancement,
    "_validate_prd_overview_analytics_insertion": _validate_prd_overview_analytics_insertion,
    "_validate_agent_q2_goals_objective_dashboard": _validate_agent_q2_goals_objective_dashboard,
    "_validate_sprint_velocity_tracker": _validate_sprint_velocity_tracker,
    "_validate_agent_team_related_documentation_index": _validate_agent_team_related_documentation_index,
    "_validate_workspace_migration_checklist": _validate_workspace_migration_checklist,
    "_validate_meeting_hub_creation": _validate_meeting_hub_creation,
    "_validate_new_hire_onboarding_creation": _validate_new_hire_onboarding_creation,
    "_validate_weekly_planning_template_creation": _validate_weekly_planning_template_creation,
    "_validate_documentation_templates_creation": _validate_documentation_templates_creation,
    "_validate_knowledge_base_creation": _validate_knowledge_base_creation,
    "_validate_team_hub_creation": _validate_team_hub_creation,
    "_validate_engineering_docs_hub_creation": _validate_engineering_docs_hub_creation,
    "_validate_company_culture_creation": _validate_company_culture_creation,
    "_validate_project_templates_hub_creation": _validate_project_templates_hub_creation,
    "_validate_feature_requests_priority_matrix": _validate_feature_requests_priority_matrix,
    "_validate_getting_started_onboarding_tracker": _validate_getting_started_onboarding_tracker,
    "_validate_product_requirements_implementation_timeline": _validate_product_requirements_implementation_timeline,
    "_validate_code_examples_swift_section": _validate_code_examples_swift_section,
    "_validate_code_examples_go_after_sql_with_stats": _validate_code_examples_go_after_sql_with_stats,
    "_validate_product_requirements_overview_critical_updates": _validate_product_requirements_overview_critical_updates,
    "_validate_project_guidelines_statistics": _validate_project_guidelines_statistics,
    "_validate_sprint_planning_retrospective": _validate_sprint_planning_retrospective,
    "_validate_sprint_planning_swap_with_metrics": _validate_sprint_planning_swap_with_metrics,
    "_validate_weekly_standup_achievements": _validate_weekly_standup_achievements,
    "_validate_product_requirements_security_considerations": _validate_product_requirements_security_considerations,
    "_validate_feature_requests_under_review": _validate_feature_requests_under_review,
    "_validate_getting_started_progress_indicator": _validate_getting_started_progress_indicator,
    "_validate_bug_tracker_under_investigation": _validate_bug_tracker_under_investigation,
    "_validate_onboarding_guide_first_week_milestones": _validate_onboarding_guide_first_week_milestones,
    "_validate_code_examples_python_guide": _validate_code_examples_python_guide,
    "_validate_code_examples_go_after_python_with_stats": _validate_code_examples_go_after_python_with_stats,
    "_validate_sprint_planning_metrics": _validate_sprint_planning_metrics,
    "_validate_weekly_standup_location_updates": _validate_weekly_standup_location_updates,
    "_validate_bug_tracker_priority_legend": _validate_bug_tracker_priority_legend,
    "_validate_code_examples_devops_section_2": _validate_code_examples_devops_section_2,
    "_validate_getting_started_enhanced_onboarding_2": _validate_getting_started_enhanced_onboarding_2,
    "_validate_sprint_planning_retrospective_variant": _validate_sprint_planning_retrospective_variant,
    "_validate_engineering_wiki_reorganization_2": _validate_engineering_wiki_reorganization_2,
    "_validate_company_handbook_swap_with_home_office": _validate_company_handbook_swap_with_home_office,
    "_validate_feature_requests_reorganization_with_calculations": _validate_feature_requests_reorganization_with_calculations,
    "_validate_bug_tracker_swap_with_stats": _validate_bug_tracker_swap_with_stats,
    "_validate_quarterly_goals_dashboard_creation": _validate_quarterly_goals_dashboard_creation,
    "_validate_workspace_analytics_dashboard_creation": _validate_workspace_analytics_dashboard_creation,
    "_validate_sprint_planning_hub_creation": _validate_sprint_planning_hub_creation,
    "_validate_weekly_standup_date_section": _validate_weekly_standup_date_section,
    "_validate_api_documentation_index_creation": _validate_api_documentation_index_creation,
    "_validate_q1_onboarding_tracker_creation": _validate_q1_onboarding_tracker_creation,
    "_validate_team_task_overview_creation": _validate_team_task_overview_creation,
    "_validate_design_system_audit_creation": _validate_design_system_audit_creation,
    "_validate_company_handbook_swap_with_bookmark": _validate_company_handbook_swap_with_bookmark,
    "_validate_project_task_analysis_creation": _validate_project_task_analysis_creation,
    "_validate_learning_path_navigator_creation": _validate_learning_path_navigator_creation,
    "_validate_q1_goals_enhancement": _validate_q1_goals_enhancement,
    "_validate_feature_requests_in_progress_section": _validate_feature_requests_in_progress_section,
    "_validate_documentation_analytics_creation": _validate_documentation_analytics_creation,
    "_validate_onboarding_interactive_checklist": _validate_onboarding_interactive_checklist,
    "_validate_sprint_planning_automation_creation": _validate_sprint_planning_automation_creation,
    "_validate_sprint_planning_post_review": _validate_sprint_planning_post_review,
    "_validate_team_performance_review_creation": _validate_team_performance_review_creation,
    "_validate_weekly_standup_mid_week_check": _validate_weekly_standup_mid_week_check,
    "_validate_sprint_planning_follow_up_status": _validate_sprint_planning_follow_up_status,
    "_validate_learning_path_tracker_creation": _validate_learning_path_tracker_creation,
    "_validate_onboarding_completion_tracker": _validate_onboarding_completion_tracker,
    "_validate_api_endpoint_reference": _validate_api_endpoint_reference,
    "_validate_design_system_reorganization": _validate_design_system_reorganization,
    "_validate_product_requirements_technical_specs": _validate_product_requirements_technical_specs,
    "_validate_product_requirements_technical_requirements": _validate_product_requirements_technical_requirements,
    "_validate_team_performance_report_meeting_analysis": _validate_team_performance_report_meeting_analysis,
    "_validate_development_resources_hub_creation": _validate_development_resources_hub_creation,
    "_validate_workspace_audit_report_creation": _validate_workspace_audit_report_creation,
    "_validate_api_documentation_versioning_2": _validate_api_documentation_versioning_2,
    "_validate_bug_analysis_report_creation": _validate_bug_analysis_report_creation,
    "_validate_sprint_planning_section_swap": _validate_sprint_planning_section_swap,
    "_validate_team_retrospective_action_items_2": _validate_team_retrospective_action_items_2,
    "_validate_design_system_child_page_restructure": _validate_design_system_child_page_restructure,
    "_validate_standard_operating_procedure_creation": _validate_standard_operating_procedure_creation,
    "_validate_weekly_standup_performance_tracking": _validate_weekly_standup_performance_tracking,
    "_validate_meeting_notes_index_creation": _validate_meeting_notes_index_creation,
    "_validate_design_system_audit_report": _validate_design_system_audit_report,
    "_validate_engineering_wiki_docker_config": _validate_engineering_wiki_docker_config,
    "_validate_company_handbook_complex_reorg": _validate_company_handbook_complex_reorg,
    "_validate_api_documentation_external_resources": _validate_api_documentation_external_resources,
    "_validate_team_resource_library_creation": _validate_team_resource_library_creation,
    "_validate_weekly_standup_blockers_section": _validate_weekly_standup_blockers_section,
    "_validate_api_documentation_authentication": _validate_api_documentation_authentication,
    "_validate_bug_tracker_severity_classification": _validate_bug_tracker_severity_classification,
    "_validate_company_handbook_culture_section_2": _validate_company_handbook_culture_section_2,
    "_validate_code_examples_advanced_patterns": _validate_code_examples_advanced_patterns,
    "_validate_product_requirements_section_swap": _validate_product_requirements_section_swap,
    "_validate_sprint_planning_velocity_calc": _validate_sprint_planning_velocity_calc,
    "_validate_code_examples_python_performance": _validate_code_examples_python_performance,
    "_validate_weekly_standup_milestones": _validate_weekly_standup_milestones,
    "_validate_team_directory_remote_members": _validate_team_directory_remote_members,
    "_validate_company_handbook_section_swap_date": _validate_company_handbook_section_swap_date,
    "_validate_company_handbook_benefits_perks": _validate_company_handbook_benefits_perks,
    "_validate_weekly_standup_sprint_priorities": _validate_weekly_standup_sprint_priorities,
    "_validate_meeting_notes_dashboard": _validate_meeting_notes_dashboard,
    "_validate_team_performance_analytics": _validate_team_performance_analytics,
    "_validate_design_system_component_examples": _validate_design_system_component_examples,
    "_validate_api_documentation_breaking_changes": _validate_api_documentation_breaking_changes,
    "_validate_project_documentation_reorg": _validate_project_documentation_reorg,
    "organise-project-planning-hub-v2": _validate_agent_organise_project_planning_hub,
    "create-documentation-structure-v2": _validate_agent_create_documentation_structure,
    "consolidate-architecture-docs-v2": _validate_agent_consolidate_architecture_docs,
    "create-documentation-overview-map-v2": _validate_agent_create_documentation_overview_map,
    "create-meeting-analytics-hub-v2": _validate_agent_create_meeting_analytics_hub,
    "create-design-system-catalog-v2": _validate_agent_create_design_system_catalog,
    "add-document-structure-overview-v2": _validate_agent_add_document_structure_overview,
    "add-sprint-goals-alignment-v2": _validate_agent_add_sprint_goals_alignment,
    "reorganize-external-resources-v2": _validate_agent_reorganize_external_resources_3,
    "add-advanced-features-checklist-v2": _validate_agent_add_advanced_features_checklist,
    "create-team-performance-dashboard-v2": _validate_agent_create_team_performance_dashboard,
    "create-team-task-dashboard-v2": _validate_agent_create_team_task_dashboard,
    "reorganize-prd-overview-sections-v2": _validate_agent_reorganize_prd_overview_sections,
    "reorganize-feature-requests-by-status-v2": _validate_agent_reorganize_feature_requests_by_status,
    "transform-standup-template-v2": _validate_agent_transform_standup_template_dynamic,
    "analyze-prd-content-metrics-v2": _validate_agent_analyze_prd_content_metrics,
    "add-onboarding-tracking-system-v2": _validate_agent_add_onboarding_tracking_system,
    "add-bug-resolution-statistics-v2": _validate_agent_add_bug_resolution_statistics,
    "add-sprint-velocity-metrics-v2": _validate_agent_add_sprint_velocity_metrics,
    "add-hot-fixes-section-v2": _validate_agent_add_hot_fixes_section,
    "reorganize-guidelines-by-color-v2": _validate_agent_reorganize_guidelines_by_color,
    "add-api-rate-limiting-section-v2": _validate_agent_add_api_rate_limiting_section,
    "create-meeting-analysis-report-v2": _validate_agent_create_meeting_analysis_report,
    "add-urgent-priority-section-v2": _validate_agent_add_urgent_priority_section,
    "add-utility-functions-section-v2": _validate_agent_add_utility_functions_section_2,
    "add-performance-reviews-section-v2": _validate_agent_add_performance_reviews_section,
    "create-architecture-summary-report-v2": _validate_agent_create_architecture_summary_report,
    "add-tutorial-enhancement-system-v2": _validate_agent_add_tutorial_enhancement_system,
    "add-advanced-patterns-section-v2": _validate_agent_add_advanced_patterns_section,
    "swap-api-sections-with-security-v2": _validate_agent_swap_api_sections_with_security,
    "reorganize-team-directory-v2": _validate_agent_reorganize_team_directory,
    "add-priority-markers-standup-template-v2": _validate_agent_add_priority_markers_standup_template,
    "create-code-quality-report-v2": _validate_agent_create_code_quality_report,
    "organize-feature-requests-dashboard-v2": _validate_agent_organize_feature_requests_dashboard,
    "add-meeting-analytics-dashboard-v2": _validate_agent_add_meeting_analytics_dashboard,
    "create-documentation-health-report-v2": _validate_agent_create_documentation_health_report,
    "enhance-sprint-planning-meeting-v2": _validate_agent_enhance_sprint_planning_meeting,
    "add-prd-executive-summary-v2": _validate_agent_add_prd_executive_summary,
    "add-sprint-metrics-section-v2": _validate_agent_add_sprint_metrics_section_2,
    "reorganize-company-handbook-v2": _validate_agent_reorganize_company_handbook_3,
    "create-meeting-archive-system-v2": _validate_agent_create_meeting_archive_system,
    "create-retrospective-analysis-v2": _validate_agent_create_retrospective_analysis,
    "add-language-statistics-v2": _validate_agent_add_language_statistics,
    "restructure-handbook-sections-v2": _validate_agent_restructure_handbook_sections,
    "add-advanced-features-section-v2": _validate_agent_add_advanced_features_section,
    "enhance-team-retrospective-v2": _validate_agent_enhance_team_retrospective,
    "create-workspace-activity-dashboard-v2": _validate_agent_create_workspace_activity_dashboard,
    "add-development-best-practices-v2": _validate_agent_add_development_best_practices,
    "add-react-examples-section-v2": _validate_agent_add_react_examples_section_3,
    "reorganize-handbook-with-performance-v2": _validate_agent_reorganize_handbook_with_performance,
    "add-code-examples-after-tips-v2": _validate_agent_add_code_examples_after_tips,
    "add-user-story-analysis-v2": _validate_agent_add_user_story_analysis,
    "add-sprint-metrics-kpis-v2": _validate_agent_add_sprint_metrics_kpis,
    "complex-handbook-reorganization-v2": _validate_agent_complex_handbook_reorganization,
    "cross-page-values-integration-v2": _validate_agent_cross_page_values_integration,
    "add-medium-priority-stats-v2": _validate_agent_add_medium_priority_stats,
    "add-handbook-update-tracking-v2": _validate_agent_add_handbook_update_tracking,
    "add-team-velocity-tracker-v2": _validate_agent_add_team_velocity_tracker,
    "create-goals-dashboard-v2": _validate_agent_create_goals_dashboard,
    "add-checklist-analysis-v2": _validate_agent_add_checklist_analysis,
    "create-team-productivity-report-v2": _validate_agent_create_team_productivity_report,
    "create-quarterly-health-report-v2": _validate_agent_create_quarterly_health_report,
    "create-onboarding-progress-tracker-v2": _validate_agent_create_onboarding_progress_tracker,
    "create-bug-triage-dashboard-v2": _validate_agent_create_bug_triage_dashboard,
    "add-team-directory-alumni-v2": _validate_agent_add_team_directory_alumni,
    "add-prd-document-navigation-v2": _validate_agent_add_prd_document_navigation,
    "add-handbook-quick-reference-v2": _validate_agent_add_handbook_quick_reference,
    "add-wiki-docker-setup-v2": _validate_agent_add_wiki_docker_setup,
    "add-python-examples-section-v2": _validate_agent_add_python_examples_section,
    "add-learning-platforms-resources-v2": _validate_agent_add_learning_platforms_resources,
    "add-mid-sprint-review-section-v2": _validate_agent_add_mid_sprint_review_section,
    "add-action-items-retrospective-v2": _validate_agent_add_action_items_retrospective,
    "enhance-onboarding-experience-v2": _validate_agent_enhance_onboarding_experience,
    "reorganize-standup-template-v2": _validate_agent_reorganize_standup_template,
    "add-product-team-section-v2": _validate_agent_add_product_team_section,
    "swap-wiki-sections-with-additions-v2": _validate_agent_swap_wiki_sections_with_additions,
    "create-external-resources-audit-v2": _validate_agent_create_external_resources_audit,
    "create-resource-library-hub-v2": _validate_agent_create_resource_library_hub,
}
