Courses Internships Relation

L3
ModelContextProtocolNotionComputer Science Student Dashboard

Connect the Courses and Internship search databases with bidirectional relations and populate with sample data.

Created by Zijian Wu
2025-07-27
Database ManipulationCross Reference LinkingTemplate Population

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-opus-4-1
0
/1
--
363.5s
21.0
420,966
4,170
425,136
Claude
claude-sonnet-4
0
/4
215.0s
24.3
630,677
5,208
635,885
Claude
claude-sonnet-4-high
0
/4
276.3s
24.8
3,201,324
5,119
3,206,443
Claude
claude-sonnet-4-low
0
/4
223.8s
22.8
1,302,297
4,775
1,307,072
DeepSeek
deepseek-chat
0
/4
267.7s
22.0
398,360
2,579
400,938
Gemini
gemini-2-5-flash
0
/4
39.4s
9.0
105,939
5,238
111,176
Gemini
gemini-2-5-pro
0
/4
56.9s
3.8
48,309
3,833
52,141
Z.ai
glm-4-5
0
/4
128.2s
18.0
280,492
3,451
283,942
OpenAI
gpt-4-1
0
/4
46.3s
8.8
74,924
1,416
76,339
OpenAI
gpt-4-1-mini
0
/4
57.4s
13.8
168,149
1,456
169,605
OpenAI
gpt-4-1-nano
0
/4
15.0s
5.5
22,003
435
22,437
OpenAI
gpt-5-high
0
/4
1913.9s
22.3
368,074
107,542
475,616
OpenAI
gpt-5-low
0
/4
912.1s
18.3
228,376
52,685
281,061
OpenAI
gpt-5-medium
0
/4
1194.0s
20.8
340,326
63,968
404,294
OpenAI
gpt-5-mini-high
0
/4
842.5s
41.5
3,492,398
61,314
3,553,712
OpenAI
gpt-5-mini-low
0
/4
48.9s
7.3
48,108
3,617
51,725
OpenAI
gpt-5-mini-medium
0
/4
303.3s
31.3
1,876,386
18,071
1,894,458
OpenAI
gpt-5-nano-high
0
/4
351.1s
7.5
101,879
78,297
180,176
OpenAI
gpt-5-nano-low
0
/4
112.9s
7.3
45,576
20,609
66,185
OpenAI
gpt-5-nano-medium
0
/4
217.2s
7.8
180,948
36,961
217,909
OpenAI
gpt-oss-120b
0
/4
11.3s
3.3
12,792
633
13,425
Grok
grok-4
0
/4
421.8s
30.0
666,277
14,370
680,646
Grok
grok-code-fast-1
0
/4
274.9s
21.8
465,036
9,449
479,549
MoonshotAI
kimi-k2-0711
0
/4
104.2s
17.5
215,842
2,218
218,060
MoonshotAI
kimi-k2-0905
0
/4
593.6s
42.5
1,560,924
6,038
1,566,962
OpenAI
o3
0
/4
489.8s
33.5
435,148
35,544
470,692
OpenAI
o4-mini
0
/4
993.7s
31.3
333,767
73,775
407,542
Qwen
qwen-3-coder-plus
0
/4
94.6s
23.5
363,352
2,677
366,028
Qwen
qwen-3-max
0
/4
83.5s
20.0
316,241
1,953
318,194

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

Your goal is to connect the Courses and Internship search databases inside the Computer Science Student Dashboard page and populate them with sample data that can be verified automatically.

Task Requirements:

  1. In the Courses database, add a new relation property named Related Internships that points to the Internship search database.
  2. Ensure the relation is bidirectional by adding a relation property in the Internship search database named Relevant Courses that points back to the Courses database.
  3. Create exactly three new pages in the Courses database with realistic computer-science course data. Each course page must include all of the following properties and values: • Code (text) – unique codes CS301, CS302, and CS303 respectively
    Name (text) – pick appropriate names (e.g., Computer Networks, Operating Systems, Machine Learning)
    Credit (number) – any positive integer
    Status (status) – choose from Planned, In Progress, or Completed
    Related Internships (relation) – link to at least one internship created in step4.
  4. Create exactly two new pages in the Internship search database with complete application information. Each internship page must include all of the following properties and values: • Company (text) – OpenAI and Google respectively
    Role (text) – Machine Learning Intern and Software Engineering Intern
    Status (status) – set to Interested
    Relevant Courses (relation) – link to one or more of the courses created in step3.
  5. Every course created in step3 must be linked to at least one internship from step4 and every internship must be linked back to at least one course.

The task is considered complete when the relation properties exist, the specified course and internship pages are present with the exact values above, and the relations correctly connect the two databases in both directions.



Verify

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

# ---------------------------------------------------------------------------
# Constants -----------------------------------------------------------------
# ---------------------------------------------------------------------------
MAIN_PAGE_TITLE = "Computer Science Student Dashboard"
COURSES_DB_TITLE = "Courses"
INTERNSHIP_DB_TITLE = "Internship search"

COURSE_CODES = {"CS301", "CS302", "CS303"}
COURSE_RELATION_NAME = "Related Internships"
INTERNSHIP_RELATION_NAME = "Relevant Courses"

INTERNSHIP_COMPANIES = {"OpenAI", "Google"}

# ---------------------------------------------------------------------------
# Helper functions -----------------------------------------------------------
# ---------------------------------------------------------------------------


def _locate_main_page(notion: Client, main_id: str | None) -> str | None:
    """Return the page_id of the dashboard page or None if not found."""
    page_id = None
    if main_id:
        found_id, obj_type = notion_utils.find_page_or_database_by_id(notion, main_id)
        if found_id and obj_type == "page":
            page_id = found_id
    if not page_id:
        page_id = notion_utils.find_page(notion, MAIN_PAGE_TITLE)
    return page_id


def _locate_database(notion: Client, parent_page_id: str, db_title: str) -> str | None:
    """Recursively search for a child database by title and return its id."""
    return notion_utils.find_database_in_block(notion, parent_page_id, db_title)


# ---------------------------------------------------------------------------
# Verification logic ---------------------------------------------------------
# ---------------------------------------------------------------------------


def verify(notion: Client, main_id: str | None = None) -> bool:
    """Verify completion of the Courses ↔ Internship relation task."""
    # ------------------------------------------------------------------
    # Locate main page and databases -----------------------------------
    # ------------------------------------------------------------------
    page_id = _locate_main_page(notion, main_id)
    if not page_id:
        print(f"Error: Page '{MAIN_PAGE_TITLE}' not found.", file=sys.stderr)
        return False

    courses_db_id = _locate_database(notion, page_id, COURSES_DB_TITLE)
    internships_db_id = _locate_database(notion, page_id, INTERNSHIP_DB_TITLE)

    if not courses_db_id:
        print(f"Error: Database '{COURSES_DB_TITLE}' not found.", file=sys.stderr)
        return False
    if not internships_db_id:
        print(f"Error: Database '{INTERNSHIP_DB_TITLE}' not found.", file=sys.stderr)
        return False

    # ------------------------------------------------------------------
    # Validate relation properties -------------------------------------
    # ------------------------------------------------------------------
    courses_db_obj = notion.databases.retrieve(database_id=courses_db_id)
    internships_db_obj = notion.databases.retrieve(database_id=internships_db_id)

    courses_props = courses_db_obj.get("properties", {})
    internships_props = internships_db_obj.get("properties", {})

    # Courses → Internships relation
    if COURSE_RELATION_NAME not in courses_props:
        print(
            f"Error: Property '{COURSE_RELATION_NAME}' missing in Courses database.",
            file=sys.stderr,
        )
        return False
    course_rel_prop = courses_props[COURSE_RELATION_NAME]
    if (
        course_rel_prop.get("type") != "relation"
        or course_rel_prop["relation"].get("database_id") != internships_db_id
    ):
        print(
            "Error: Courses relation property is not configured correctly.",
            file=sys.stderr,
        )
        return False

    # Internships → Courses relation
    if INTERNSHIP_RELATION_NAME not in internships_props:
        print(
            f"Error: Property '{INTERNSHIP_RELATION_NAME}' missing in Internship search database.",
            file=sys.stderr,
        )
        return False
    intern_rel_prop = internships_props[INTERNSHIP_RELATION_NAME]
    if (
        intern_rel_prop.get("type") != "relation"
        or intern_rel_prop["relation"].get("database_id") != courses_db_id
    ):
        print(
            "Error: Internship relation property is not configured correctly.",
            file=sys.stderr,
        )
        return False

    # ------------------------------------------------------------------
    # Validate course pages --------------------------------------------
    # ------------------------------------------------------------------
    course_pages = notion.databases.query(database_id=courses_db_id).get("results", [])

    valid_course_count = 0
    course_page_id_set = set()
    internship_ids_seen: set[str] = set()

    for page in course_pages:
        props = page.get("properties", {})
        code_rts = props.get("Code", {}).get("rich_text", [])
        code_val = "".join(rt.get("plain_text", "") for rt in code_rts).strip()
        if code_val not in COURSE_CODES:
            continue  # not one of the new course entries we care about

        # Check required scalar props
        title_rts = props.get("Name", {}).get("title", [])
        name_ok = bool("".join(rt.get("plain_text", "") for rt in title_rts).strip())
        credits_ok = props.get("Credit", {}).get("number") is not None
        status_name = props.get("Status", {}).get("status", {}).get("name", "")
        status_allowed = {"planned", "in progress", "completed"}
        status_ok = status_name.lower() in status_allowed

        # Relation must point to at least one internship
        relations = props.get(COURSE_RELATION_NAME, {}).get("relation", [])
        if not (name_ok and credits_ok and status_ok and relations):
            print(
                f"Error: Course '{code_val}' is missing required property values or relations, or wrong values.",
                file=sys.stderr,
            )
            return False

        # Collect IDs for further mutual check
        course_page_id_set.add(page["id"])
        internship_ids_seen.update(rel["id"] for rel in relations)
        valid_course_count += 1

    if valid_course_count != 3:
        print(
            f"Error: Expected exactly 3 new course pages with codes {COURSE_CODES}, found {valid_course_count}.",
            file=sys.stderr,
        )
        return False

    # ------------------------------------------------------------------
    # Validate internship pages ----------------------------------------
    # ------------------------------------------------------------------
    internship_pages = notion.databases.query(database_id=internships_db_id).get(
        "results", []
    )

    valid_intern_count = 0
    internship_page_ids = set()
    course_ids_seen_from_intern: set[str] = set()

    for page in internship_pages:
        props = page.get("properties", {})
        company_rts = props.get("Company", {}).get("rich_text", [])
        company = "".join(rt.get("plain_text", "") for rt in company_rts).strip()
        if company not in INTERNSHIP_COMPANIES:
            continue  # not one of the two new internships

        role_rts = props.get("Role", {}).get("title", [])
        role_ok = bool("".join(rt.get("plain_text", "") for rt in role_rts).strip())
        status_name = props.get("Status", {}).get("status", {}).get("name", "")
        status_ok = status_name.lower() == "interested"
        relations = props.get(INTERNSHIP_RELATION_NAME, {}).get("relation", [])

        if not (role_ok and status_ok and relations):
            print(
                f"Error: Internship at '{company}' is missing required property values or relations, or wrong values.",
                file=sys.stderr,
            )
            return False

        internship_page_ids.add(page["id"])
        course_ids_seen_from_intern.update(rel["id"] for rel in relations)
        valid_intern_count += 1

    if valid_intern_count != 2:
        print(
            f"Error: Expected exactly 2 new internship pages for companies {INTERNSHIP_COMPANIES}, found {valid_intern_count}.",
            file=sys.stderr,
        )
        return False

    # ------------------------------------------------------------------
    # Mutual relation consistency --------------------------------------
    # ------------------------------------------------------------------
    # Each relation from courses should point to one of the two internships identified
    if not internship_ids_seen.issubset(internship_page_ids):
        print(
            "Error: Some course relations point to pages outside the expected internships.",
            file=sys.stderr,
        )
        return False

    # Each relation from internships should point back to the three course pages identified
    if not course_ids_seen_from_intern.issubset(course_page_id_set):
        print(
            "Error: Some internship relations point to pages outside the expected courses.",
            file=sys.stderr,
        )
        return False

    print(
        "Success: Verified bidirectional relations, course and internship entries as required."
    )
    return True


# ---------------------------------------------------------------------------
# CLI entry-point -----------------------------------------------------------
# ---------------------------------------------------------------------------


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


if __name__ == "__main__":
    main()