feat(lessons): a lesson is yours to keep current too (#4195)
CI & Build / Python lint (push) Successful in 4s
CI & Build / Plugin hooks (push) Successful in 12s
CI & Build / integration (push) Successful in 52s
CI & Build / TypeScript typecheck (push) Successful in 55s
CI & Build / Python tests (push) Successful in 1m49s
CI & Build / Build & push image (push) Successful in 29s

The lesson kind shipped with every mechanism for growing and nothing
telling a session to use them. `learned_from` is a list on purpose, the
dedup gate hands back an existing id rather than minting a twin, and
`update_lesson` already names re-keying a bad trigger as the edit that
pays most. None of that was reachable as a habit.

The exclusivity claim was the bug. The skill said "a preference is the
one record you keep current yourself", and by naming only preferences it
put lessons outside the habit. That sentence is now "a preference is
yours to keep current", which says the same thing about preferences
without saying anything false about lessons.

Beside it, a paragraph on what growing a lesson means: another incident
added to what taught it, a claim stated more exactly, or a trigger
re-keyed to the situation that really fired. Written as a practice
rather than a prohibition (rule 165) — the reader is named as the one
person placed to judge the trigger, because they are standing in the
situation it claims to name.

`get_lesson` carries the same prompt at the moment it bites: a session
reading a lesson inside the situation it names is the only reader who
can tell whether the trigger is keyed to what actually fired.

The guidance-ownership registry gains the topic and re-points the
preference topic's statement, since the phrase it pinned is the sentence
this change rewrites — the module asks for exactly that, in the same
commit. No index marker: the index names session-start reflexes and this
one fires mid-work, so `_INSTRUCTIONS` stays at 1998/2000.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01821k5B3Ysecp9fNYs92Kuy
This commit is contained in:
2026-09-19 23:17:20 -04:00
co-authored by Claude Opus 5
parent 1c438b27e2
commit 26a757ecfe
4 changed files with 43 additions and 12 deletions
+11 -1
View File
@@ -178,7 +178,17 @@ async def create_lesson(
async def get_lesson(lesson_id: int) -> dict:
"""Fetch one lesson by id, with its trigger and sources read back out."""
"""Fetch one lesson by id, with its trigger and sources read back out.
IF THIS LESSON JUST PROVED ITSELF, IT IS WORTH MORE THAN IT SAYS. You are
reading it inside the situation it names, which makes you the one reader
who can tell whether its trigger is keyed to what actually fired and
whether its claim covers what you are seeing. `update_lesson` takes
another incident into `learned_from`, a claim stated more exactly, or a
re-keyed trigger — and the trigger is the edit that pays most, because a
lesson keyed to a situation nobody is in looks exactly like one nobody
needed.
"""
uid = current_user_id()
note = await lessons_svc.get_lesson(uid, lesson_id)
if note is None: