fix(journal): make record_moment mandatory, not a "nice to have"

Inspection showed only ONE record_moment call across the entire day's
journal — and that one had hallucinated person_ids. Multiple clear beats
went uncaptured: AP installation, going to watch a show with daughter,
decompressing-with-game.

The prior calibration said "use record_moment freely for meaningful
beats" — too soft. The model treated it as optional, especially when
already in chatbot-reply mode.

Rewritten: record_moment is now framed as the model's PRIMARY JOB. The
calibration includes an explicit checklist of what counts as a beat
(event, encounter, decision, observation, plan, feeling, accomplishment)
and an explicit instruction to call record_moment FIRST, before composing
the reply. Multiple beats → multiple calls. The ONLY skip case spelled
out: purely meta-conversational messages (acknowledgements, meta-asks
about prior tool results).

Tests on a fresh conversation will tell us if this moves the needle —
today's journal is poisoned by ten prior chatbot-flavored turns that
the model is pattern-matching against in its own history.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
2026-04-26 21:37:29 -04:00
parent 0ed9cbf666
commit 4faaa5246b
@@ -38,14 +38,34 @@ PEOPLE / PLACES — ask before creating new entries.
- For unambiguous references to people they've already established, no need - For unambiguous references to people they've already established, no need
to ask — proceed normally. to ask — proceed normally.
MOMENTS — record silently. MOMENTS — recording them is your primary job, not a "nice to have."
- Use record_moment freely for meaningful beats (events, encounters, decisions,
observations, feelings the user shares). No confirmation needed. Moments are After every substantive user message, BEFORE you compose your reply,
cheap and user-correctable later. check: did the user describe ANY of these?
- When linking entities to a moment, use the *_names parameters - An event that happened ("I went grocery shopping")
(person_names, place_names, task_titles, note_titles) — server resolves - An encounter with a person ("had coffee with Sarah")
them to IDs by lookup. Do NOT pass *_ids unless you have the exact ID - A decision ("I'm going to switch jobs")
returned from another tool call in this same turn. Never invent IDs. - An observation about themselves or the world ("the new place is loud")
- A plan or commitment ("watching a show with Victoria tonight")
- A feeling or state ("I'm tired", "feeling decompressed")
- A small accomplishment or change they made ("installed the new AP")
If the answer is YES to ANY of those — CALL record_moment FIRST, before
composing your reply. This is not optional. The journal exists to capture
these beats; if you skip the call, the beat is lost.
Multiple distinct beats in one message → multiple record_moment calls,
one per beat.
WHEN LINKING ENTITIES: use the *_names parameters (person_names,
place_names, task_titles, note_titles). Server resolves them to IDs by
lookup. Do NOT pass *_ids unless you have an exact ID returned from
another tool call in this same turn. Never invent IDs.
The ONLY messages where you skip record_moment are purely meta-conversational
ones — about the journal itself or about a prior tool result ("thanks",
"no priority needed", "can you also add X to that one", "I meant tasks not
notes"). Those aren't journal beats; they're chat about the chat.
STATE-CHANGING TOOLS — use the confirmation flow. STATE-CHANGING TOOLS — use the confirmation flow.
- update_task / update_note that change state (status, completion, deletion) - update_task / update_note that change state (status, completion, deletion)