Study Session Tracker

L3
ModelContextProtocolNotionComputer Science Student Dashboard

Create a new study-session entry in the Habit tracker section with four unchecked to-do items.

Created by Zijian Wu
2025-07-27
Content OrganizationVisual FormattingStatus Tracking

Model Ranking

Click on the dots to view the trajectory of each task run
Model
Run Results
Pass@4
Pass^4
Avg Time
Avg Turns
Input Tokens
Output Tokens
Total Tokens
Claude
claude-4-1-opus
0
/1
--
275.6s
16.0
330,908
3,221
334,129
Claude
claude-4-sonnet
0
/4
134.2s
14.5
320,890
3,127
324,017
DeepSeek
deepseek-chat
0
/4
115.9s
11.0
142,734
994
143,728
Gemini
gemini-2-5-pro
0
/4
107.7s
3.8
24,659
5,965
30,624
OpenAI
gpt-5
0
/4
221.5s
6.8
81,413
9,910
91,322
Grok
grok-4
0
/4
32.5s
-
-
-
-
MoonshotAI
k2
0
/4
163.0s
18.0
363,345
2,088
365,433
OpenAI
o3
0
/4
55.2s
9.3
78,283
2,588
80,871
Qwen
qwen-3-coder
0
/4
94.9s
16.3
276,978
1,306
278,284

Task State

Notion Workspace
This task is executed based on this Notion workspace
This workspace is cloned from notion official template marketplace.View Original Template

Instruction



Verify

*.py
Python
import sys
from notion_client import Client
from tasks.utils import notion_utils
from typing import Dict


def _normalize_string(s: str) -> str:
    """Replace non-breaking space with regular space for safe comparison."""
    return s.replace("\xa0", " ")


def verify(notion: Client, main_id: str | None = None) -> bool:
    """Verify that the new study-session entry for 2025-01-29 was added correctly.

    The script checks that:
    1. A bold date-mention with start=2025-01-29 exists.
    2. The mention sits after the 2022-09-02 section but before the divider that originally
       followed that section.
    3. Exactly four specified to-do items follow the new date mention and they are all unchecked.
    """

    # ---------------------------------------------------------------------
    # Locate the main page -------------------------------------------------
    # ---------------------------------------------------------------------
    page_id: str | None = None

    if main_id:
        found_id, object_type = notion_utils.find_page_or_database_by_id(
            notion, main_id
        )
        if found_id and object_type == "page":
            page_id = found_id

    if not page_id:
        page_id = notion_utils.find_page(notion, "Computer Science Student Dashboard")

    if not page_id:
        print(
            "Error: Page 'Computer Science Student Dashboard' not found.",
            file=sys.stderr,
        )
        return False

    # ---------------------------------------------------------------------
    # Fetch all blocks under the page (flattened order) --------------------
    # ---------------------------------------------------------------------
    all_blocks = notion_utils.get_all_blocks_recursively(notion, page_id)

    # ---------------------------------------------------------------------
    # Locate reference blocks ---------------------------------------------
    # ---------------------------------------------------------------------
    TARGET_DATE = "2025-01-29"
    PREVIOUS_DATE = "2022-09-02"

    index_previous_date: int | None = None
    index_new_date: int | None = None
    index_divider_after_previous: int | None = None

    for idx, block in enumerate(all_blocks):
        # Divider detection (we care only about the first divider that appears after
        # the 2022-09-02 block)
        if block.get("type") == "divider":
            if index_previous_date is not None and index_divider_after_previous is None:
                index_divider_after_previous = idx

        # We only need to inspect paragraph blocks that contain a date mention
        if block.get("type") != "paragraph":
            continue

        rich_text_list = block["paragraph"].get("rich_text", [])
        for rt in rich_text_list:
            if (
                rt.get("type") != "mention"
                or rt.get("mention", {}).get("type") != "date"
            ):
                continue

            date_start = rt["mention"]["date"].get("start")

            if date_start == PREVIOUS_DATE and index_previous_date is None:
                index_previous_date = idx

            if date_start == TARGET_DATE and index_new_date is None:
                index_new_date = idx
                # (1) Verify bold annotation
                if not rt.get("annotations", {}).get("bold", False):
                    print(
                        "Error: The 2025-01-29 date mention is not bold.",
                        file=sys.stderr,
                    )
                    return False

    # Ensure all reference indices were found
    if index_previous_date is None:
        print("Error: Could not locate the 2022-09-02 date section.", file=sys.stderr)
        return False
    if index_divider_after_previous is None:
        print(
            "Error: Could not locate the divider that follows the 2022-09-02 section.",
            file=sys.stderr,
        )
        return False
    if index_new_date is None:
        print(
            "Error: Could not locate the new 2025-01-29 date mention.", file=sys.stderr
        )
        return False

    # (2) Verify ordering
    if not (index_previous_date < index_new_date < index_divider_after_previous):
        print(
            "Error: The 2025-01-29 section is positioned incorrectly.", file=sys.stderr
        )
        return False

    # ---------------------------------------------------------------------
    # Verify to-do items under the new date section ------------------------
    # ---------------------------------------------------------------------
    expected_texts = [
        "🧠 Review algorithms for technical interview",
        "📚 Study database systems chapter 7",
        "⚡ Practice system design problems",
        "🎯 Complete data structures assignment",
    ]
    expected_todos: Dict[str, bool] = {
        _normalize_string(t): False for t in expected_texts
    }

    # Look through the blocks that lie between the new date mention and the divider
    for block in all_blocks[index_new_date + 1 : index_divider_after_previous]:
        if block.get("type") != "to_do":
            # Any non to-do block inside this range indicates mis-placement.
            # We simply ignore it – correctness is determined by presence of required to-dos.
            continue

        plain_text = notion_utils.get_block_plain_text(block).strip()
        plain_text_norm = _normalize_string(plain_text)
        if plain_text_norm in expected_todos:
            # (3a) Verify the to-do is unchecked
            if block["to_do"].get("checked", False):
                print(f"Error: To-do '{plain_text}' is checked.", file=sys.stderr)
                return False
            expected_todos[plain_text_norm] = True

    missing_items = [text for text, found in expected_todos.items() if not found]
    if missing_items:
        print(f"Error: Missing to-do items: {missing_items}", file=sys.stderr)
        return False

    # ---------------------------------------------------------------------
    # Success --------------------------------------------------------------
    # ---------------------------------------------------------------------
    print("Success: Study session for 2025-01-29 added correctly.")
    return True


# -------------------------------------------------------------------------
# Command-line entry-point -------------------------------------------------
# -------------------------------------------------------------------------


def main() -> None:
    notion = notion_utils.get_notion_client()
    main_id = sys.argv[1] if len(sys.argv) > 1 else None

    if verify(notion, main_id):
        sys.exit(0)
    else:
        sys.exit(1)


if __name__ == "__main__":
    main()