Daily Itinerary Overview
L3
NotionJapan Travel Planner
Create a comprehensive daily itinerary overview page to organize Japan travel plans with structured day-by-day activities.
Created by Xiangyan Liu
2025-07-27
Database ManipulationData AggregationReport GenerationVisual 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 |
---|---|---|---|---|---|---|---|---|
gpt-5 | 1 /4 | 647.8s | 10.0 | 673,432 | 28,625 | 702,056 | ||
claude-4-1-opus | 0 /1 | - | - | 127.2s | 5.0 | 369,809 | 3,078 | 372,887 |
claude-4-sonnet | 0 /4 | 116.8s | 8.0 | 460,737 | 4,206 | 464,942 | ||
deepseek-chat | 0 /4 | 280.5s | 11.8 | 782,394 | 2,623 | 785,017 | ||
gemini-2-5-pro | 0 /4 | 36.0s | 1.8 | 55,665 | 1,896 | 57,561 | ||
grok-4 | 0 /4 | - | - | - | - | - | ||
k2 | 0 /4 | 145.4s | 5.0 | 163,726 | 1,095 | 164,821 | ||
o3 | 0 /4 | 116.7s | 6.0 | 185,878 | 6,543 | 192,421 | ||
qwen-3-coder | 0 /4 | 247.0s | 18.8 | 1,673,351 | 3,009 | 1,676,361 |
Task State
Instruction
Verify
Python
import sys
import re
from notion_client import Client
from tasks.utils import notion_utils
def verify_todo_database_correspondence(all_blocks, activities_by_day, _):
"""
Verify that to-do items in the overview page correspond exactly to database activities.
"""
# Extract to-do items organized by day from the overview page
todos_by_day = {"Day 1": [], "Day 2": [], "Day 3": []}
current_day = None
checked_todos_count = 0
for block in all_blocks:
block_type = block.get("type")
block_text = notion_utils.get_block_plain_text(block)
# Track which day section we're in
if block_type == "heading_2":
if "🌅 Day 1" in block_text:
current_day = "Day 1"
elif "🌆 Day 2" in block_text:
current_day = "Day 2"
elif "🌃 Day 3" in block_text:
current_day = "Day 3"
else:
current_day = None # Reset for non-day headings
# Collect to-do items under day headings
elif block_type == "to_do" and current_day:
to_do_data = block.get("to_do", {})
is_checked = to_do_data.get("checked", False)
if is_checked:
checked_todos_count += 1
todos_by_day[current_day].append(
{"text": block_text, "checked": is_checked}
)
# Verify each day's activities match
for day in ["Day 1", "Day 2", "Day 3"]:
db_activities = activities_by_day[day]
page_todos = todos_by_day[day]
# Check if counts match
if len(db_activities) != len(page_todos):
print(
f"Error: {day} activity count mismatch. Database has {len(db_activities)} activities, page has {len(page_todos)} to-dos.",
file=sys.stderr,
)
return False
# Verify each database activity has corresponding to-do
for db_activity in db_activities:
expected_format = f"{db_activity['name']}"
if db_activity["city"]:
expected_format += f" - {db_activity['city']}"
# Find matching to-do item
matching_todo = None
for todo in page_todos:
if (
expected_format in todo["text"]
or db_activity["name"] in todo["text"]
):
matching_todo = todo
break
if not matching_todo:
print(
f"Error: {day} - Database activity '{expected_format}' not found in to-do list.",
file=sys.stderr,
)
return False
# Verify checked status matches visited status
if db_activity["visited"] != matching_todo["checked"]:
status_desc = "checked" if db_activity["visited"] else "unchecked"
actual_desc = "checked" if matching_todo["checked"] else "unchecked"
print(
f"Error: {day} - Activity '{db_activity['name']}' should be {status_desc} but is {actual_desc}.",
file=sys.stderr,
)
return False
# Verify summary count matches checked to-dos
for block in all_blocks:
if block.get("type") == "paragraph":
block_text = notion_utils.get_block_plain_text(block)
if "Total activities visited (from Day 1 to Day 3): 8" in block_text:
print(
f"Success: Daily Itinerary Overview page created with correct structure. All {checked_todos_count} visited activities match database."
)
return True
print(
f"Error: Summary shows incorrect visited activity count. Expected: {checked_todos_count} (based on checked to-do items)",
file=sys.stderr,
)
return False
def verify(notion: Client, main_id: str = None) -> bool:
"""
Verifies that the Daily Itinerary Overview page has been created correctly.
"""
# Find the main Japan Travel Planner page
page_id = 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, "Japan Travel Planner")
if not page_id:
print("Error: Main 'Japan Travel Planner' page not found.", file=sys.stderr)
return False
# Find the Daily Itinerary Overview child page
overview_page_id = None
try:
# Get all child pages of the main page
response = notion.search(
query="Daily Itinerary Overview",
filter={"property": "object", "value": "page"},
)
for result in response.get("results", []):
# Check if this page is a child of the main page
parent = result.get("parent", {})
if parent.get("type") == "page_id" and parent.get("page_id") == page_id:
overview_page_id = result["id"]
break
if not overview_page_id:
# Alternative method: check page title directly
for result in response.get("results", []):
title_list = (
result.get("properties", {}).get("title", {}).get("title", [])
)
for title_obj in title_list:
if "Daily Itinerary Overview" in title_obj.get("plain_text", ""):
overview_page_id = result["id"]
break
if overview_page_id:
break
except Exception as e:
print(
f"Error searching for Daily Itinerary Overview page: {e}", file=sys.stderr
)
return False
if not overview_page_id:
print(
"Error: 'Daily Itinerary Overview' page not found as child of main page.",
file=sys.stderr,
)
return False
# Get all blocks from the overview page
all_blocks = notion_utils.get_all_blocks_recursively(notion, overview_page_id)
# Required content to verify - must appear in this exact order
required_headings_sequence = [
("📅 Daily Itinerary Overview", "heading_1"),
("📊 Trip Summary", "heading_2"),
("🌅 Day 1", "heading_2"),
("🌆 Day 2", "heading_2"),
("🌃 Day 3", "heading_2"),
]
found_headings_in_order = []
found_summary = False
summary_has_correct_format = False
found_todo_items = False
# Check each block and track heading sequence
for block in all_blocks:
block_text = notion_utils.get_block_plain_text(block)
block_type = block.get("type")
# Check for required headings in sequence
for heading_text, expected_type in required_headings_sequence:
if heading_text in block_text and block_type == expected_type:
found_headings_in_order.append((heading_text, expected_type))
# Check for trip summary paragraph
if (
block_type == "paragraph"
and "Total activities visited (from Day 1 to Day 3):" in block_text
):
found_summary = True
# Check if the format is correct (contains a number)
if re.search(
r"Total activities visited \(from Day 1 to Day 3\):\s*\d+", block_text
):
summary_has_correct_format = True
# Check for to-do list items (activities under day headings)
if block_type == "to_do":
found_todo_items = True
# Check if to-do items follow the format "Activity Name - City"
if " - " in block_text:
# Format appears to be correct (contains dash separator)
pass
# Verify all required headings are found in correct sequence
if len(found_headings_in_order) != len(required_headings_sequence):
missing_headings = []
for heading_text, heading_type in required_headings_sequence:
if (heading_text, heading_type) not in found_headings_in_order:
missing_headings.append(f"{heading_text} ({heading_type})")
print(f"Error: Missing required headings: {missing_headings}", file=sys.stderr)
return False
# Verify headings appear in correct order
for i, (found_heading, found_type) in enumerate(found_headings_in_order):
expected_heading, expected_type = required_headings_sequence[i]
if found_heading != expected_heading or found_type != expected_type:
print(
f"Error: Headings not in correct order. Expected '{expected_heading}' ({expected_type}) at position {i + 1}, but found '{found_heading}' ({found_type})",
file=sys.stderr,
)
return False
# Verify trip summary exists and has correct format
if not found_summary:
print(
"Error: Trip summary paragraph with 'Total activities visite' not found.",
file=sys.stderr,
)
return False
if not summary_has_correct_format:
print(
"Error: Trip summary does not have correct format 'Total activities visited: [NUMBER]'.",
file=sys.stderr,
)
return False
# Verify to-do list items exist (activities should be in to-do format)
if not found_todo_items:
print(
"Error: No to-do list items found. Activities should be listed as to-do items under day headings.",
file=sys.stderr,
)
return False
# Additional verification: Check if Travel Itinerary database exists and has data
try:
itinerary_db_id = notion_utils.find_database_in_block(
notion, page_id, "Travel Itinerary"
)
if not itinerary_db_id:
itinerary_db_id = notion_utils.find_database(notion, "Travel Itinerary")
if itinerary_db_id:
# Query the database to get all activities
db_response = notion.databases.query(database_id=itinerary_db_id)
db_activities = db_response.get("results", [])
# Organize database activities by day
activities_by_day = {"Day 1": [], "Day 2": [], "Day 3": []}
visited_count = 0
for result in db_activities:
properties = result.get("properties", {})
# Extract activity info
activity_info = {"name": "", "city": "", "visited": False, "day": None}
for prop_name, prop_value in properties.items():
prop_type = prop_value.get("type")
# Get activity name (usually from title property)
if prop_type == "title" and prop_value.get("title"):
activity_info["name"] = prop_value["title"][0]["plain_text"]
# Get city info
elif "city" in prop_name.lower() and prop_type in [
"rich_text",
"select",
]:
if prop_type == "rich_text" and prop_value.get("rich_text"):
activity_info["city"] = prop_value["rich_text"][0][
"plain_text"
]
elif prop_type == "select" and prop_value.get("select"):
activity_info["city"] = prop_value["select"]["name"]
# Get visited status
elif prop_type == "checkbox":
if prop_value.get("checkbox"):
activity_info["visited"] = True
visited_count += 1
# Get day info
elif "day" in prop_name.lower() and prop_type in [
"select",
"rich_text",
]:
if prop_type == "select" and prop_value.get("select"):
day_value = prop_value["select"]["name"]
if day_value in activities_by_day:
activity_info["day"] = day_value
elif prop_type == "rich_text" and prop_value.get("rich_text"):
day_value = prop_value["rich_text"][0]["plain_text"]
if day_value in activities_by_day:
activity_info["day"] = day_value
# Add to appropriate day if day is specified
if activity_info["day"] and activity_info["name"]:
activities_by_day[activity_info["day"]].append(activity_info)
# Now verify to-do items match database activities
return verify_todo_database_correspondence(
all_blocks, activities_by_day, visited_count
)
else:
print(
"Warning: Travel Itinerary database not found, using to-do items for count verification."
)
# Count checked to-do items in the overview page even without database
checked_todos_count = 0
for block in all_blocks:
if block.get("type") == "to_do":
to_do_data = block.get("to_do", {})
if to_do_data.get("checked", False):
checked_todos_count += 1
# Verify the summary shows the correct visited count based on checked to-dos
for block in all_blocks:
if block.get("type") == "paragraph":
block_text = notion_utils.get_block_plain_text(block)
if f"Total activities visited: {checked_todos_count}" in block_text:
print(
f"Success: Daily Itinerary Overview page created with correct structure and {checked_todos_count} visited activities."
)
return True
print(
f"Error: Summary shows incorrect visited activity count. Expected: {checked_todos_count} (based on checked to-do items)",
file=sys.stderr,
)
return False
except Exception as e:
print(f"Warning: Could not verify activity count: {e}")
print("Success: Daily Itinerary Overview page created with correct structure.")
return True
def main():
"""
Executes the verification process and exits with a status code.
"""
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()