fix(calendar-tool): anchor today's weekday in prompts + verify expected_weekday on create/update

A user asked Fable to schedule "this Friday at 8am" on Wednesday 4/29
2026. The model picked 4/30 (Thursday) and confidently labeled it
"Friday." The TZ pipeline did everything correctly given the model's
date — the bug was upstream: the model was guessing weekdays from ISO
dates without an anchor, and the calendar tools had no way to verify.

Three layered fixes:

1. **System prompts now name the weekday alongside the ISO date.**
   Both the journal-conversation prompt and the general chat prompt
   used to say "Today is 2026-04-29 (America/New_York)." They now say
   "Today is Wednesday, 2026-04-29 (...)." LLMs are unreliable at
   deriving weekday names from ISO dates; supplying the name removes
   the guess.

2. **`expected_weekday` parameter on create_event / update_event.**
   When the model passes `expected_weekday="friday"`, the backend
   computes the resolved start_date's weekday in the user's local
   timezone and rejects mismatches with a self-correcting error
   ("Date 2026-04-30 falls on Thursday, not Friday. Recompute..."),
   without creating the event. The check is local-aware: a Friday
   23:00 event in Tokyo crosses midnight UTC but the local view
   stays Friday, and the validator respects that.

3. **Tool descriptions instruct echo-and-confirm.** create_event and
   update_event descriptions now tell the model: when the user names
   a weekday, state the resolved date in the reply BEFORE calling
   the tool, and pass `expected_weekday`. Costs nothing in code,
   reinforces the validator.

6 new tests — match success, mismatch rejection (with create/update
not invoked), omitted-param backcompat, invalid weekday name, local-
not-UTC weekday computation, and the update_event variant. All 18
calendar-tool tests + 33 event-related tests pass; ruff clean.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
2026-04-29 08:43:32 -04:00
co-authored by Claude Opus 4.7
parent 611c940527
commit 03d725ea3e
4 changed files with 276 additions and 5 deletions
@@ -134,7 +134,11 @@ async def build_journal_system_prompt(
static_block = f"{JOURNAL_PERSONA}\n\n{JOURNAL_CALIBRATION}"
today_iso = day_date.isoformat()
tz_block = f"Today is {today_iso} ({user_timezone})."
# Include the day-of-week explicitly. LLMs are unreliable at deriving
# weekday names from ISO dates, which causes "this Friday" / "next
# Monday" to land on the wrong calendar day.
weekday = day_date.strftime("%A")
tz_block = f"Today is {weekday}, {today_iso} ({user_timezone})."
profile_context = await build_profile_context(user_id)
profile_section = f"\n\n{profile_context}" if profile_context else ""